You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/09/21 16:27:31 UTC
[35/52] [partial] ignite git commit: IGNITE-1513: Moved .Net.
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
new file mode 100644
index 0000000..f294cbd
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableFullTypeDescriptor.cs
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Full type descriptor.
+ /// </summary>
+ internal class PortableFullTypeDescriptor : IPortableTypeDescriptor
+ {
+ /** Type. */
+ private readonly Type _type;
+
+ /** Type ID. */
+ private readonly int _typeId;
+
+ /** Type name. */
+ private readonly string _typeName;
+
+ /** User type flag. */
+ private readonly bool _userType;
+
+ /** Name converter. */
+ private readonly IPortableNameMapper _nameConverter;
+
+ /** Mapper. */
+ private readonly IPortableIdMapper _mapper;
+
+ /** Serializer. */
+ private readonly IPortableSerializer _serializer;
+
+ /** Metadata enabled flag. */
+ private readonly bool _metaEnabled;
+
+ /** Whether to cache deserialized value in IPortableObject */
+ private readonly bool _keepDeserialized;
+
+ /** Affinity field key name. */
+ private readonly string _affKeyFieldName;
+
+ /** Typed handler. */
+ private readonly object _typedHandler;
+
+ /** Untyped handler. */
+ private readonly PortableSystemWriteDelegate _untypedHandler;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="type">Type.</param>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="typeName">Type name.</param>
+ /// <param name="userType">User type flag.</param>
+ /// <param name="nameConverter">Name converter.</param>
+ /// <param name="mapper">Mapper.</param>
+ /// <param name="serializer">Serializer.</param>
+ /// <param name="metaEnabled">Metadata enabled flag.</param>
+ /// <param name="keepDeserialized">Whether to cache deserialized value in IPortableObject</param>
+ /// <param name="affKeyFieldName">Affinity field key name.</param>
+ /// <param name="typedHandler">Typed handler.</param>
+ /// <param name="untypedHandler">Untyped handler.</param>
+ public PortableFullTypeDescriptor(
+ Type type,
+ int typeId,
+ string typeName,
+ bool userType,
+ IPortableNameMapper nameConverter,
+ IPortableIdMapper mapper,
+ IPortableSerializer serializer,
+ bool metaEnabled,
+ bool keepDeserialized,
+ string affKeyFieldName,
+ object typedHandler,
+ PortableSystemWriteDelegate untypedHandler)
+ {
+ _type = type;
+ _typeId = typeId;
+ _typeName = typeName;
+ _userType = userType;
+ _nameConverter = nameConverter;
+ _mapper = mapper;
+ _serializer = serializer;
+ _metaEnabled = metaEnabled;
+ _keepDeserialized = keepDeserialized;
+ _affKeyFieldName = affKeyFieldName;
+ _typedHandler = typedHandler;
+ _untypedHandler = untypedHandler;
+ }
+
+ /// <summary>
+ /// Type.
+ /// </summary>
+ public Type Type
+ {
+ get { return _type; }
+ }
+
+ /// <summary>
+ /// Type ID.
+ /// </summary>
+ public int TypeId
+ {
+ get { return _typeId; }
+ }
+
+ /// <summary>
+ /// Type name.
+ /// </summary>
+ public string TypeName
+ {
+ get { return _typeName; }
+ }
+
+ /// <summary>
+ /// User type flag.
+ /// </summary>
+ public bool UserType
+ {
+ get { return _userType; }
+ }
+
+ /// <summary>
+ /// Metadata enabled flag.
+ /// </summary>
+ public bool MetadataEnabled
+ {
+ get { return _metaEnabled; }
+ }
+
+ /// <summary>
+ /// Whether to cache deserialized value in IPortableObject
+ /// </summary>
+ public bool KeepDeserialized
+ {
+ get { return _keepDeserialized; }
+ }
+
+ /// <summary>
+ /// Name converter.
+ /// </summary>
+ public IPortableNameMapper NameConverter
+ {
+ get { return _nameConverter; }
+ }
+
+ /// <summary>
+ /// Mapper.
+ /// </summary>
+ public IPortableIdMapper Mapper
+ {
+ get { return _mapper; }
+ }
+
+ /// <summary>
+ /// Serializer.
+ /// </summary>
+ public IPortableSerializer Serializer
+ {
+ get { return _serializer; }
+ }
+
+ /// <summary>
+ /// Affinity key field name.
+ /// </summary>
+ public string AffinityKeyFieldName
+ {
+ get { return _affKeyFieldName; }
+ }
+
+ /// <summary>
+ /// Typed handler.
+ /// </summary>
+ public object TypedHandler
+ {
+ get { return _typedHandler; }
+ }
+
+ /// <summary>
+ /// Untyped handler.
+ /// </summary>
+ public PortableSystemWriteDelegate UntypedHandler
+ {
+ get { return _untypedHandler; }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableHandleDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableHandleDictionary.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableHandleDictionary.cs
new file mode 100644
index 0000000..32e1e02
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableHandleDictionary.cs
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+
+ /// <summary>
+ /// Object handle dictionary.
+ /// </summary>
+ internal class PortableHandleDictionary<TK, TV>
+ {
+ /** Initial array sizes. */
+ private const int InitialSize = 7;
+
+ /** Dictionary. */
+ private Dictionary<TK, TV> _dict;
+
+ /** First key. */
+ private readonly TK _key1;
+
+ /** First value. */
+ private readonly TV _val1;
+
+ /** Second key. */
+ private TK _key2;
+
+ /** Second value. */
+ private TV _val2;
+
+ /** Third key. */
+ private TK _key3;
+
+ /** Third value. */
+ private TV _val3;
+
+ /// <summary>
+ /// Constructor with initial key-value pair.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <param name="val">Value.</param>
+ [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors"),
+ SuppressMessage("ReSharper", "DoNotCallOverridableMethodsInConstructor")]
+ public PortableHandleDictionary(TK key, TV val)
+ {
+ Debug.Assert(!Equals(key, EmptyKey));
+
+ _key1 = key;
+ _val1 = val;
+
+ _key2 = EmptyKey;
+ _key3 = EmptyKey;
+ }
+
+ /// <summary>
+ /// Add value to dictionary.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <param name="val">Value.</param>
+ public void Add(TK key, TV val)
+ {
+ Debug.Assert(!Equals(key, EmptyKey));
+
+ if (Equals(_key2, EmptyKey))
+ {
+ _key2 = key;
+ _val2 = val;
+
+ return;
+ }
+
+ if (Equals(_key3, EmptyKey))
+ {
+ _key3 = key;
+ _val3 = val;
+
+ return;
+ }
+
+ if (_dict == null)
+ _dict = new Dictionary<TK, TV>(InitialSize);
+
+ _dict[key] = val;
+ }
+
+ /// <summary>
+ /// Try getting value for the given key.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <param name="val">Value.</param>
+ /// <returns>True if key was found.</returns>
+ public bool TryGetValue(TK key, out TV val)
+ {
+ Debug.Assert(!Equals(key, EmptyKey));
+
+ if (Equals(key, _key1))
+ {
+ val = _val1;
+
+ return true;
+ }
+
+ if (Equals(key, _key2))
+ {
+ val = _val2;
+
+ return true;
+ }
+
+ if (Equals(key, _key3))
+ {
+ val = _val3;
+
+ return true;
+ }
+
+ if (_dict == null)
+ {
+ val = default(TV);
+
+ return false;
+ }
+
+ return _dict.TryGetValue(key, out val);
+ }
+
+ /// <summary>
+ /// Merge data from another dictionary without overwrite.
+ /// </summary>
+ /// <param name="that">Other dictionary.</param>
+ public void Merge(PortableHandleDictionary<TK, TV> that)
+ {
+ Debug.Assert(that != null, "that == null");
+
+ AddIfAbsent(that._key1, that._val1);
+ AddIfAbsent(that._key2, that._val2);
+ AddIfAbsent(that._key3, that._val3);
+
+ if (that._dict == null)
+ return;
+
+ foreach (var pair in that._dict)
+ AddIfAbsent(pair.Key, pair.Value);
+ }
+
+ /// <summary>
+ /// Add key/value pair to the bucket if absent.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <param name="val">Value.</param>
+ private void AddIfAbsent(TK key, TV val)
+ {
+ if (Equals(key, EmptyKey))
+ return;
+
+ if (Equals(key, _key1) || Equals(key, _key2) || Equals(key, _key3))
+ return;
+
+ if (_dict == null || !_dict.ContainsKey(key))
+ Add(key, val);
+ }
+
+ /// <summary>
+ /// Gets the empty key.
+ /// </summary>
+ protected virtual TK EmptyKey
+ {
+ get { return default(TK); }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshalAwareSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshalAwareSerializer.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshalAwareSerializer.cs
new file mode 100644
index 0000000..e3c7523
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshalAwareSerializer.cs
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable serializer which only supports <see cref="IPortableMarshalAware"/> types with a default ctor.
+ /// Does not use reflection.
+ /// </summary>
+ internal class PortableMarshalAwareSerializer : IPortableSerializer
+ {
+ /// <summary>
+ /// Default instance.
+ /// </summary>
+ public static readonly PortableMarshalAwareSerializer Instance = new PortableMarshalAwareSerializer();
+
+ /** <inheritdoc /> */
+ public void WritePortable(object obj, IPortableWriter writer)
+ {
+ ((IPortableMarshalAware)obj).WritePortable(writer);
+ }
+
+ /** <inheritdoc /> */
+ public void ReadPortable(object obj, IPortableReader reader)
+ {
+ ((IPortableMarshalAware)obj).ReadPortable(reader);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs
new file mode 100644
index 0000000..6286ebb
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMarshaller.cs
@@ -0,0 +1,599 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Apache.Ignite.Core.Impl.Cache;
+ using Apache.Ignite.Core.Impl.Cache.Query.Continuous;
+ using Apache.Ignite.Core.Impl.Common;
+ using Apache.Ignite.Core.Impl.Compute;
+ using Apache.Ignite.Core.Impl.Compute.Closure;
+ using Apache.Ignite.Core.Impl.Datastream;
+ using Apache.Ignite.Core.Impl.Messaging;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+ using Apache.Ignite.Core.Impl.Portable.Metadata;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable marshaller implementation.
+ /// </summary>
+ internal class PortableMarshaller
+ {
+ /** Portable configuration. */
+ private readonly PortableConfiguration _cfg;
+
+ /** Type to descriptor map. */
+ private readonly IDictionary<Type, IPortableTypeDescriptor> _typeToDesc =
+ new Dictionary<Type, IPortableTypeDescriptor>();
+
+ /** Type name to descriptor map. */
+ private readonly IDictionary<string, IPortableTypeDescriptor> _typeNameToDesc =
+ new Dictionary<string, IPortableTypeDescriptor>();
+
+ /** ID to descriptor map. */
+ private readonly IDictionary<long, IPortableTypeDescriptor> _idToDesc =
+ new Dictionary<long, IPortableTypeDescriptor>();
+
+ /** Cached metadatas. */
+ private volatile IDictionary<int, PortableMetadataHolder> _metas =
+ new Dictionary<int, PortableMetadataHolder>();
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="cfg">Configurtaion.</param>
+ public PortableMarshaller(PortableConfiguration cfg)
+ {
+ // Validation.
+ if (cfg == null)
+ cfg = new PortableConfiguration();
+
+ if (cfg.TypeConfigurations == null)
+ cfg.TypeConfigurations = new List<PortableTypeConfiguration>();
+
+ foreach (PortableTypeConfiguration typeCfg in cfg.TypeConfigurations)
+ {
+ if (string.IsNullOrEmpty(typeCfg.TypeName))
+ throw new PortableException("Type name cannot be null or empty: " + typeCfg);
+
+ if (typeCfg.AssemblyName != null && typeCfg.AssemblyName.Length == 0)
+ throw new PortableException("Assembly name cannot be empty string: " + typeCfg);
+ }
+
+ // Define predefined types.
+ AddPredefinedType(typeof(bool), PortableUtils.TypeBool, PortableSystemHandlers.WriteHndBoolTyped, PortableSystemHandlers.WriteHndBool);
+ AddPredefinedType(typeof(byte), PortableUtils.TypeByte, PortableSystemHandlers.WriteHndByteTyped, PortableSystemHandlers.WriteHndByte);
+ AddPredefinedType(typeof(short), PortableUtils.TypeShort, PortableSystemHandlers.WriteHndShortTyped, PortableSystemHandlers.WriteHndShort);
+ AddPredefinedType(typeof(char), PortableUtils.TypeChar, PortableSystemHandlers.WriteHndCharTyped, PortableSystemHandlers.WriteHndChar);
+ AddPredefinedType(typeof(int), PortableUtils.TypeInt, PortableSystemHandlers.WriteHndIntTyped, PortableSystemHandlers.WriteHndInt);
+ AddPredefinedType(typeof(long), PortableUtils.TypeLong, PortableSystemHandlers.WriteHndLongTyped, PortableSystemHandlers.WriteHndLong);
+ AddPredefinedType(typeof(float), PortableUtils.TypeFloat, PortableSystemHandlers.WriteHndFloatTyped, PortableSystemHandlers.WriteHndFloat);
+ AddPredefinedType(typeof(double), PortableUtils.TypeDouble, PortableSystemHandlers.WriteHndDoubleTyped, PortableSystemHandlers.WriteHndDouble);
+ AddPredefinedType(typeof(string), PortableUtils.TypeString, PortableSystemHandlers.WriteHndStringTyped, PortableSystemHandlers.WriteHndString);
+ AddPredefinedType(typeof(decimal), PortableUtils.TypeDecimal, PortableSystemHandlers.WriteHndDecimalTyped, PortableSystemHandlers.WriteHndDecimal);
+ AddPredefinedType(typeof(DateTime), PortableUtils.TypeDate, PortableSystemHandlers.WriteHndDateTyped, PortableSystemHandlers.WriteHndDate);
+ AddPredefinedType(typeof(Guid), PortableUtils.TypeGuid, PortableSystemHandlers.WriteHndGuidTyped, PortableSystemHandlers.WriteHndGuid);
+
+ // TODO: Remove this registration
+ AddPredefinedType(typeof(PortableUserObject), PortableUtils.TypePortable, PortableSystemHandlers.WriteHndPortableTyped,
+ PortableSystemHandlers.WriteHndPortable);
+
+ AddPredefinedType(typeof(bool[]), PortableUtils.TypeArrayBool, PortableSystemHandlers.WriteHndBoolArrayTyped,
+ PortableSystemHandlers.WriteHndBoolArray);
+ AddPredefinedType(typeof(byte[]), PortableUtils.TypeArrayByte, PortableSystemHandlers.WriteHndByteArrayTyped,
+ PortableSystemHandlers.WriteHndByteArray);
+ AddPredefinedType(typeof(short[]), PortableUtils.TypeArrayShort, PortableSystemHandlers.WriteHndShortArrayTyped,
+ PortableSystemHandlers.WriteHndShortArray);
+ AddPredefinedType(typeof(char[]), PortableUtils.TypeArrayChar, PortableSystemHandlers.WriteHndCharArrayTyped,
+ PortableSystemHandlers.WriteHndCharArray);
+ AddPredefinedType(typeof(int[]), PortableUtils.TypeArrayInt, PortableSystemHandlers.WriteHndIntArrayTyped,
+ PortableSystemHandlers.WriteHndIntArray);
+ AddPredefinedType(typeof(long[]), PortableUtils.TypeArrayLong, PortableSystemHandlers.WriteHndLongArrayTyped,
+ PortableSystemHandlers.WriteHndLongArray);
+ AddPredefinedType(typeof(float[]), PortableUtils.TypeArrayFloat, PortableSystemHandlers.WriteHndFloatArrayTyped,
+ PortableSystemHandlers.WriteHndFloatArray);
+ AddPredefinedType(typeof(double[]), PortableUtils.TypeArrayDouble, PortableSystemHandlers.WriteHndDoubleArrayTyped,
+ PortableSystemHandlers.WriteHndDoubleArray);
+ AddPredefinedType(typeof(decimal[]), PortableUtils.TypeArrayDecimal, PortableSystemHandlers.WriteHndDecimalArrayTyped,
+ PortableSystemHandlers.WriteHndDecimalArray);
+ AddPredefinedType(typeof(string[]), PortableUtils.TypeArrayString, PortableSystemHandlers.WriteHndStringArrayTyped,
+ PortableSystemHandlers.WriteHndStringArray);
+ AddPredefinedType(typeof(DateTime?[]), PortableUtils.TypeArrayDate, PortableSystemHandlers.WriteHndDateArrayTyped,
+ PortableSystemHandlers.WriteHndDateArray);
+ AddPredefinedType(typeof(Guid?[]), PortableUtils.TypeArrayGuid, PortableSystemHandlers.WriteHndGuidArrayTyped,
+ PortableSystemHandlers.WriteHndGuidArray);
+
+ // Define system types. They use internal reflective stuff, so configuration doesn't affect them.
+ AddSystemTypes();
+
+ // 2. Define user types.
+ var dfltSerializer = cfg.DefaultSerializer == null ? new PortableReflectiveSerializer() : null;
+
+ var typeResolver = new TypeResolver();
+
+ ICollection<PortableTypeConfiguration> typeCfgs = cfg.TypeConfigurations;
+
+ if (typeCfgs != null)
+ foreach (PortableTypeConfiguration typeCfg in typeCfgs)
+ AddUserType(cfg, typeCfg, typeResolver, dfltSerializer);
+
+ ICollection<string> types = cfg.Types;
+
+ if (types != null)
+ foreach (string type in types)
+ AddUserType(cfg, new PortableTypeConfiguration(type), typeResolver, dfltSerializer);
+
+ if (cfg.DefaultSerializer == null)
+ cfg.DefaultSerializer = dfltSerializer;
+
+ _cfg = cfg;
+ }
+
+ /// <summary>
+ /// Gets or sets the backing grid.
+ /// </summary>
+ public Ignite Ignite { get; set; }
+
+ /// <summary>
+ /// Marshal object.
+ /// </summary>
+ /// <param name="val">Value.</param>
+ /// <returns>Serialized data as byte array.</returns>
+ public byte[] Marshal(object val)
+ {
+ PortableHeapStream stream = new PortableHeapStream(128);
+
+ Marshal(val, stream);
+
+ return stream.ArrayCopy();
+ }
+
+ /// <summary>
+ /// Marshal object.
+ /// </summary>
+ /// <param name="val">Value.</param>
+ /// <param name="stream">Output stream.</param>
+ /// <returns>Collection of metadatas (if any).</returns>
+ private void Marshal<T>(T val, IPortableStream stream)
+ {
+ PortableWriterImpl writer = StartMarshal(stream);
+
+ writer.Write(val);
+
+ FinishMarshal(writer);
+ }
+
+ /// <summary>
+ /// Start marshal session.
+ /// </summary>
+ /// <param name="stream">Stream.</param>
+ /// <returns>Writer.</returns>
+ public PortableWriterImpl StartMarshal(IPortableStream stream)
+ {
+ return new PortableWriterImpl(this, stream);
+ }
+
+ /// <summary>
+ /// Finish marshal session.
+ /// </summary>
+ /// <param name="writer">Writer.</param>
+ /// <returns>Dictionary with metadata.</returns>
+ public void FinishMarshal(IPortableWriter writer)
+ {
+ var meta = ((PortableWriterImpl) writer).Metadata();
+
+ var ignite = Ignite;
+
+ if (ignite != null && meta != null && meta.Count > 0)
+ ignite.PutMetadata(meta);
+ }
+
+ /// <summary>
+ /// Unmarshal object.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="data">Data array.</param>
+ /// <param name="keepPortable">Whether to keep portables as portables.</param>
+ /// <returns>
+ /// Object.
+ /// </returns>
+ public T Unmarshal<T>(byte[] data, bool keepPortable)
+ {
+ return Unmarshal<T>(new PortableHeapStream(data), keepPortable);
+ }
+
+ /// <summary>
+ /// Unmarshal object.
+ /// </summary>
+ /// <param name="data">Data array.</param>
+ /// <param name="mode">The mode.</param>
+ /// <returns>
+ /// Object.
+ /// </returns>
+ public T Unmarshal<T>(byte[] data, PortableMode mode = PortableMode.Deserialize)
+ {
+ return Unmarshal<T>(new PortableHeapStream(data), mode);
+ }
+
+ /// <summary>
+ /// Unmarshal object.
+ /// </summary>
+ /// <param name="stream">Stream over underlying byte array with correct position.</param>
+ /// <param name="keepPortable">Whether to keep portables as portables.</param>
+ /// <returns>
+ /// Object.
+ /// </returns>
+ public T Unmarshal<T>(IPortableStream stream, bool keepPortable)
+ {
+ return Unmarshal<T>(stream, keepPortable ? PortableMode.KeepPortable : PortableMode.Deserialize, null);
+ }
+
+ /// <summary>
+ /// Unmarshal object.
+ /// </summary>
+ /// <param name="stream">Stream over underlying byte array with correct position.</param>
+ /// <param name="mode">The mode.</param>
+ /// <returns>
+ /// Object.
+ /// </returns>
+ public T Unmarshal<T>(IPortableStream stream, PortableMode mode = PortableMode.Deserialize)
+ {
+ return Unmarshal<T>(stream, mode, null);
+ }
+
+ /// <summary>
+ /// Unmarshal object.
+ /// </summary>
+ /// <param name="stream">Stream over underlying byte array with correct position.</param>
+ /// <param name="mode">The mode.</param>
+ /// <param name="builder">Builder.</param>
+ /// <returns>
+ /// Object.
+ /// </returns>
+ public T Unmarshal<T>(IPortableStream stream, PortableMode mode, PortableBuilderImpl builder)
+ {
+ return new PortableReaderImpl(this, _idToDesc, stream, mode, builder).Deserialize<T>();
+ }
+
+ /// <summary>
+ /// Start unmarshal session.
+ /// </summary>
+ /// <param name="stream">Stream.</param>
+ /// <param name="keepPortable">Whether to keep portables as portables.</param>
+ /// <returns>
+ /// Reader.
+ /// </returns>
+ public PortableReaderImpl StartUnmarshal(IPortableStream stream, bool keepPortable)
+ {
+ return new PortableReaderImpl(this, _idToDesc, stream,
+ keepPortable ? PortableMode.KeepPortable : PortableMode.Deserialize, null);
+ }
+
+ /// <summary>
+ /// Start unmarshal session.
+ /// </summary>
+ /// <param name="stream">Stream.</param>
+ /// <param name="mode">The mode.</param>
+ /// <returns>Reader.</returns>
+ public PortableReaderImpl StartUnmarshal(IPortableStream stream, PortableMode mode = PortableMode.Deserialize)
+ {
+ return new PortableReaderImpl(this, _idToDesc, stream, mode, null);
+ }
+
+ /// <summary>
+ /// Gets metadata for the given type ID.
+ /// </summary>
+ /// <param name="typeId">Type ID.</param>
+ /// <returns>Metadata or null.</returns>
+ public IPortableMetadata Metadata(int typeId)
+ {
+ if (Ignite != null)
+ {
+ IPortableMetadata meta = Ignite.Metadata(typeId);
+
+ if (meta != null)
+ return meta;
+ }
+
+ return PortableMetadataImpl.EmptyMeta;
+ }
+
+ /// <summary>
+ /// Gets metadata handler for the given type ID.
+ /// </summary>
+ /// <param name="desc">Type descriptor.</param>
+ /// <returns>Metadata handler.</returns>
+ public IPortableMetadataHandler MetadataHandler(IPortableTypeDescriptor desc)
+ {
+ PortableMetadataHolder holder;
+
+ if (!_metas.TryGetValue(desc.TypeId, out holder))
+ {
+ lock (this)
+ {
+ if (!_metas.TryGetValue(desc.TypeId, out holder))
+ {
+ IDictionary<int, PortableMetadataHolder> metas0 =
+ new Dictionary<int, PortableMetadataHolder>(_metas);
+
+ holder = desc.MetadataEnabled ? new PortableMetadataHolder(desc.TypeId,
+ desc.TypeName, desc.AffinityKeyFieldName) : null;
+
+ metas0[desc.TypeId] = holder;
+
+ _metas = metas0;
+ }
+ }
+ }
+
+ if (holder != null)
+ {
+ ICollection<int> ids = holder.FieldIds();
+
+ bool newType = ids.Count == 0 && !holder.Saved();
+
+ return new PortableHashsetMetadataHandler(ids, newType);
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Callback invoked when metadata has been sent to the server and acknowledged by it.
+ /// </summary>
+ /// <param name="newMetas"></param>
+ public void OnMetadataSent(IDictionary<int, IPortableMetadata> newMetas)
+ {
+ foreach (KeyValuePair<int, IPortableMetadata> metaEntry in newMetas)
+ {
+ PortableMetadataImpl meta = (PortableMetadataImpl) metaEntry.Value;
+
+ IDictionary<int, Tuple<string, int>> mergeInfo =
+ new Dictionary<int, Tuple<string, int>>(meta.FieldsMap().Count);
+
+ foreach (KeyValuePair<string, int> fieldMeta in meta.FieldsMap())
+ {
+ int fieldId = PortableUtils.FieldId(metaEntry.Key, fieldMeta.Key, null, null);
+
+ mergeInfo[fieldId] = new Tuple<string, int>(fieldMeta.Key, fieldMeta.Value);
+ }
+
+ _metas[metaEntry.Key].Merge(mergeInfo);
+ }
+ }
+
+ /// <summary>
+ /// Gets descriptor for type.
+ /// </summary>
+ /// <param name="type">Type.</param>
+ /// <returns>Descriptor.</returns>
+ public IPortableTypeDescriptor Descriptor(Type type)
+ {
+ IPortableTypeDescriptor desc;
+
+ _typeToDesc.TryGetValue(type, out desc);
+
+ return desc;
+ }
+
+ /// <summary>
+ /// Gets descriptor for type name.
+ /// </summary>
+ /// <param name="typeName">Type name.</param>
+ /// <returns>Descriptor.</returns>
+ public IPortableTypeDescriptor Descriptor(string typeName)
+ {
+ IPortableTypeDescriptor desc;
+
+ return _typeNameToDesc.TryGetValue(typeName, out desc) ? desc :
+ new PortableSurrogateTypeDescriptor(_cfg, typeName);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="userType"></param>
+ /// <param name="typeId"></param>
+ /// <returns></returns>
+ public IPortableTypeDescriptor Descriptor(bool userType, int typeId)
+ {
+ IPortableTypeDescriptor desc;
+
+ return _idToDesc.TryGetValue(PortableUtils.TypeKey(userType, typeId), out desc) ? desc :
+ userType ? new PortableSurrogateTypeDescriptor(_cfg, typeId) : null;
+ }
+
+ /// <summary>
+ /// Add user type.
+ /// </summary>
+ /// <param name="cfg">Configuration.</param>
+ /// <param name="typeCfg">Type configuration.</param>
+ /// <param name="typeResolver">The type resolver.</param>
+ /// <param name="dfltSerializer">The default serializer.</param>
+ private void AddUserType(PortableConfiguration cfg, PortableTypeConfiguration typeCfg,
+ TypeResolver typeResolver, IPortableSerializer dfltSerializer)
+ {
+ // Get converter/mapper/serializer.
+ IPortableNameMapper nameMapper = typeCfg.NameMapper ?? cfg.DefaultNameMapper;
+
+ IPortableIdMapper idMapper = typeCfg.IdMapper ?? cfg.DefaultIdMapper;
+
+ bool metaEnabled = typeCfg.MetadataEnabled ?? cfg.DefaultMetadataEnabled;
+
+ bool keepDeserialized = typeCfg.KeepDeserialized ?? cfg.DefaultKeepDeserialized;
+
+ // Try resolving type.
+ Type type = typeResolver.ResolveType(typeCfg.TypeName, typeCfg.AssemblyName);
+
+ if (type != null)
+ {
+ // Type is found.
+ var typeName = GetTypeName(type);
+
+ int typeId = PortableUtils.TypeId(typeName, nameMapper, idMapper);
+
+ var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer
+ ?? GetPortableMarshalAwareSerializer(type) ?? dfltSerializer;
+
+ var refSerializer = serializer as PortableReflectiveSerializer;
+
+ if (refSerializer != null)
+ refSerializer.Register(type, typeId, nameMapper, idMapper);
+
+ AddType(type, typeId, typeName, true, metaEnabled, keepDeserialized, nameMapper, idMapper, serializer,
+ typeCfg.AffinityKeyFieldName, null, null);
+ }
+ else
+ {
+ // Type is not found.
+ string typeName = PortableUtils.SimpleTypeName(typeCfg.TypeName);
+
+ int typeId = PortableUtils.TypeId(typeName, nameMapper, idMapper);
+
+ AddType(null, typeId, typeName, true, metaEnabled, keepDeserialized, nameMapper, idMapper, null,
+ typeCfg.AffinityKeyFieldName, null, null);
+ }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="PortableMarshalAwareSerializer"/> for a type if it is compatible.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns>Resulting <see cref="PortableMarshalAwareSerializer"/>, or null.</returns>
+ private static IPortableSerializer GetPortableMarshalAwareSerializer(Type type)
+ {
+ return type.GetInterfaces().Contains(typeof (IPortableMarshalAware))
+ ? PortableMarshalAwareSerializer.Instance
+ : null;
+ }
+
+ /// <summary>
+ /// Add predefined type.
+ /// </summary>
+ /// <param name="type">Type.</param>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="typedHandler">Typed handler.</param>
+ /// <param name="untypedHandler">Untyped handler.</param>
+ private void AddPredefinedType(Type type, int typeId, object typedHandler,
+ PortableSystemWriteDelegate untypedHandler)
+ {
+ AddType(type, typeId, GetTypeName(type), false, false, false, null, null, null, null, typedHandler,
+ untypedHandler);
+ }
+
+ /// <summary>
+ /// Add type.
+ /// </summary>
+ /// <param name="type">Type.</param>
+ /// <param name="typeId">Type ID.</param>
+ /// <param name="typeName">Type name.</param>
+ /// <param name="userType">User type flag.</param>
+ /// <param name="metaEnabled">Metadata enabled flag.</param>
+ /// <param name="keepDeserialized">Whether to cache deserialized value in IPortableObject</param>
+ /// <param name="nameMapper">Name mapper.</param>
+ /// <param name="idMapper">ID mapper.</param>
+ /// <param name="serializer">Serializer.</param>
+ /// <param name="affKeyFieldName">Affinity key field name.</param>
+ /// <param name="typedHandler">Typed handler.</param>
+ /// <param name="untypedHandler">Untyped handler.</param>
+ private void AddType(Type type, int typeId, string typeName, bool userType, bool metaEnabled,
+ bool keepDeserialized, IPortableNameMapper nameMapper, IPortableIdMapper idMapper,
+ IPortableSerializer serializer, string affKeyFieldName, object typedHandler,
+ PortableSystemWriteDelegate untypedHandler)
+ {
+ long typeKey = PortableUtils.TypeKey(userType, typeId);
+
+ if (_idToDesc.ContainsKey(typeKey))
+ {
+ string type1 = _idToDesc[typeKey].Type != null ? _idToDesc[typeKey].Type.AssemblyQualifiedName : null;
+ string type2 = type != null ? type.AssemblyQualifiedName : null;
+
+ throw new PortableException("Conflicting type IDs [type1=" + type1 + ", type2=" + type2 +
+ ", typeId=" + typeId + ']');
+ }
+
+ if (userType && _typeNameToDesc.ContainsKey(typeName))
+ throw new PortableException("Conflicting type name: " + typeName);
+
+ IPortableTypeDescriptor descriptor =
+ new PortableFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, serializer,
+ metaEnabled, keepDeserialized, affKeyFieldName, typedHandler, untypedHandler);
+
+ if (type != null)
+ _typeToDesc[type] = descriptor;
+
+ if (userType)
+ _typeNameToDesc[typeName] = descriptor;
+
+ _idToDesc[typeKey] = descriptor;
+ }
+
+ /// <summary>
+ /// Adds a predefined system type.
+ /// </summary>
+ private void AddSystemType<T>(byte typeId, Func<PortableReaderImpl, T> ctor) where T : IPortableWriteAware
+ {
+ var type = typeof(T);
+
+ var serializer = new PortableSystemTypeSerializer<T>(ctor);
+
+ AddType(type, typeId, GetTypeName(type), false, false, false, null, null, serializer, null, null, null);
+ }
+
+ /// <summary>
+ /// Adds predefined system types.
+ /// </summary>
+ private void AddSystemTypes()
+ {
+ AddSystemType(PortableUtils.TypeNativeJobHolder, w => new ComputeJobHolder(w));
+ AddSystemType(PortableUtils.TypeComputeJobWrapper, w => new ComputeJobWrapper(w));
+ AddSystemType(PortableUtils.TypePortableJobResHolder, w => new PortableResultWrapper(w));
+ AddSystemType(PortableUtils.TypeIgniteProxy, w => new IgniteProxy());
+ AddSystemType(PortableUtils.TypeComputeOutFuncJob, w => new ComputeOutFuncJob(w));
+ AddSystemType(PortableUtils.TypeComputeOutFuncWrapper, w => new ComputeOutFuncWrapper(w));
+ AddSystemType(PortableUtils.TypeComputeFuncWrapper, w => new ComputeFuncWrapper(w));
+ AddSystemType(PortableUtils.TypeComputeFuncJob, w => new ComputeFuncJob(w));
+ AddSystemType(PortableUtils.TypeComputeActionJob, w => new ComputeActionJob(w));
+ AddSystemType(PortableUtils.TypeContinuousQueryRemoteFilterHolder, w => new ContinuousQueryFilterHolder(w));
+ AddSystemType(PortableUtils.TypeSerializableHolder, w => new SerializableObjectHolder(w));
+ AddSystemType(PortableUtils.TypeCacheEntryProcessorHolder, w => new CacheEntryProcessorHolder(w));
+ AddSystemType(PortableUtils.TypeCacheEntryPredicateHolder, w => new CacheEntryFilterHolder(w));
+ AddSystemType(PortableUtils.TypeMessageFilterHolder, w => new MessageFilterHolder(w));
+ AddSystemType(PortableUtils.TypePortableOrSerializableHolder, w => new PortableOrSerializableObjectHolder(w));
+ AddSystemType(PortableUtils.TypeStreamReceiverHolder, w => new StreamReceiverHolder(w));
+ }
+
+ /// <summary>
+ /// Gets the name of the type.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns>
+ /// Simple type name for non-generic types; simple type name with appended generic arguments for generic types.
+ /// </returns>
+ private static string GetTypeName(Type type)
+ {
+ if (!type.IsGenericType)
+ return type.Name;
+
+ var args = type.GetGenericArguments().Select(GetTypeName).Aggregate((x, y) => x + "," + y);
+
+ return string.Format("{0}[{1}]", type.Name, args);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMode.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMode.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMode.cs
new file mode 100644
index 0000000..670b091
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableMode.cs
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ /// <summary>
+ /// Portable mode.
+ /// </summary>
+ internal enum PortableMode
+ {
+ /// <summary>
+ /// Deserialize top-level portable objects, but leave nested portable objects in portable form.
+ /// </summary>
+ Deserialize,
+
+ /// <summary>
+ /// Keep portable objects in portable form.
+ /// </summary>
+ KeepPortable,
+
+ /// <summary>
+ /// Always return IPortableObject.
+ /// </summary>
+ ForcePortable
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHandle.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHandle.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHandle.cs
new file mode 100644
index 0000000..f2c3842
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHandle.cs
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ /// <summary>
+ /// Object handle. Wraps a single value.
+ /// </summary>
+ internal class PortableObjectHandle
+ {
+ /** Value. */
+ private readonly object _val;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PortableObjectHandle"/> class.
+ /// </summary>
+ /// <param name="val">The value.</param>
+ public PortableObjectHandle(object val)
+ {
+ _val = val;
+ }
+
+ /// <summary>
+ /// Gets the value.
+ /// </summary>
+ public object Value
+ {
+ get { return _val; }
+ }
+
+ /** <inheritdoc /> */
+ public override bool Equals(object obj)
+ {
+ var that = obj as PortableObjectHandle;
+
+ return that != null && _val == that._val;
+ }
+
+ /** <inheritdoc /> */
+ public override int GetHashCode()
+ {
+ return _val != null ? _val.GetHashCode() : 0;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableOrSerializableObjectHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableOrSerializableObjectHolder.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableOrSerializableObjectHolder.cs
new file mode 100644
index 0000000..06ccf8b
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableOrSerializableObjectHolder.cs
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Wraps portable/serializable item in a portable.
+ /// </summary>
+ internal class PortableOrSerializableObjectHolder : IPortableWriteAware
+ {
+ /** */
+ private readonly object _item;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SerializableObjectHolder"/> class.
+ /// </summary>
+ /// <param name="item">The item to wrap.</param>
+ public PortableOrSerializableObjectHolder(object item)
+ {
+ _item = item;
+ }
+
+ /// <summary>
+ /// Gets or sets the item to wrap.
+ /// </summary>
+ public object Item
+ {
+ get { return _item; }
+ }
+
+ /** <inheritDoc /> */
+ public void WritePortable(IPortableWriter writer)
+ {
+ var writer0 = (PortableWriterImpl)writer.RawWriter();
+
+ writer0.DetachNext();
+
+ PortableUtils.WritePortableOrSerializable(writer0, Item);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PortableOrSerializableObjectHolder"/> class.
+ /// </summary>
+ /// <param name="reader">The reader.</param>
+ public PortableOrSerializableObjectHolder(IPortableReader reader)
+ {
+ _item = PortableUtils.ReadPortableOrSerializable<object>((PortableReaderImpl)reader.RawReader());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderHandleDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderHandleDictionary.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderHandleDictionary.cs
new file mode 100644
index 0000000..6a765c3
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderHandleDictionary.cs
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ /// <summary>
+ /// Object handle dictionary for PortableReader.
+ /// </summary>
+ internal class PortableReaderHandleDictionary : PortableHandleDictionary<int, object>
+ {
+ /// <summary>
+ /// Constructor with initial key-value pair.
+ /// </summary>
+ /// <param name="key">Key.</param>
+ /// <param name="val">Value.</param>
+ public PortableReaderHandleDictionary(int key, object val)
+ : base(key, val)
+ {
+ // No-op.
+ }
+
+ /** <inheritdoc /> */
+ protected override int EmptyKey
+ {
+ get { return -1; }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/f2eb16cd/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
new file mode 100644
index 0000000..176ca27
--- /dev/null
+++ b/modules/platform/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
@@ -0,0 +1,1013 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Portable
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.IO;
+ using System.Runtime.Serialization;
+ using Apache.Ignite.Core.Impl.Common;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+ using Apache.Ignite.Core.Portable;
+
+ /// <summary>
+ /// Portable reader implementation.
+ /// </summary>
+ internal class PortableReaderImpl : IPortableReader, IPortableRawReader
+ {
+ /** Marshaller. */
+ private readonly PortableMarshaller _marsh;
+
+ /** Type descriptors. */
+ private readonly IDictionary<long, IPortableTypeDescriptor> _descs;
+
+ /** Parent builder. */
+ private readonly PortableBuilderImpl _builder;
+
+ /** Handles. */
+ private PortableReaderHandleDictionary _hnds;
+
+ /** Current type ID. */
+ private int _curTypeId;
+
+ /** Current position. */
+ private int _curPos;
+
+ /** Current raw data offset. */
+ private int _curRawOffset;
+
+ /** Current converter. */
+ private IPortableNameMapper _curConverter;
+
+ /** Current mapper. */
+ private IPortableIdMapper _curMapper;
+
+ /** Current raw flag. */
+ private bool _curRaw;
+
+ /** Detach flag. */
+ private bool _detach;
+
+ /** Portable read mode. */
+ private PortableMode _mode;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="marsh">Marshaller.</param>
+ /// <param name="descs">Descriptors.</param>
+ /// <param name="stream">Input stream.</param>
+ /// <param name="mode">The mode.</param>
+ /// <param name="builder">Builder.</param>
+ public PortableReaderImpl
+ (PortableMarshaller marsh,
+ IDictionary<long, IPortableTypeDescriptor> descs,
+ IPortableStream stream,
+ PortableMode mode,
+ PortableBuilderImpl builder)
+ {
+ _marsh = marsh;
+ _descs = descs;
+ _mode = mode;
+ _builder = builder;
+
+ Stream = stream;
+ }
+
+ /// <summary>
+ /// Gets the marshaller.
+ /// </summary>
+ public PortableMarshaller Marshaller
+ {
+ get { return _marsh; }
+ }
+
+ /** <inheritdoc /> */
+ public IPortableRawReader RawReader()
+ {
+ MarkRaw();
+
+ return this;
+ }
+
+ /** <inheritdoc /> */
+ public bool ReadBoolean(string fieldName)
+ {
+ return ReadField(fieldName, r => r.ReadBoolean());
+ }
+
+ /** <inheritdoc /> */
+ public bool ReadBoolean()
+ {
+ return Stream.ReadBool();
+ }
+
+ /** <inheritdoc /> */
+ public bool[] ReadBooleanArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadBooleanArray);
+ }
+
+ /** <inheritdoc /> */
+ public bool[] ReadBooleanArray()
+ {
+ return Read(PortableUtils.ReadBooleanArray);
+ }
+
+ /** <inheritdoc /> */
+ public byte ReadByte(string fieldName)
+ {
+ return ReadField(fieldName, ReadByte);
+ }
+
+ /** <inheritdoc /> */
+ public byte ReadByte()
+ {
+ return Stream.ReadByte();
+ }
+
+ /** <inheritdoc /> */
+ public byte[] ReadByteArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadByteArray);
+ }
+
+ /** <inheritdoc /> */
+ public byte[] ReadByteArray()
+ {
+ return Read(PortableUtils.ReadByteArray);
+ }
+
+ /** <inheritdoc /> */
+ public short ReadShort(string fieldName)
+ {
+ return ReadField(fieldName, ReadShort);
+ }
+
+ /** <inheritdoc /> */
+ public short ReadShort()
+ {
+ return Stream.ReadShort();
+ }
+
+ /** <inheritdoc /> */
+ public short[] ReadShortArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadShortArray);
+ }
+
+ /** <inheritdoc /> */
+ public short[] ReadShortArray()
+ {
+ return Read(PortableUtils.ReadShortArray);
+ }
+
+ /** <inheritdoc /> */
+ public char ReadChar(string fieldName)
+ {
+ return ReadField(fieldName, ReadChar);
+ }
+
+ /** <inheritdoc /> */
+ public char ReadChar()
+ {
+ return Stream.ReadChar();
+ }
+
+ /** <inheritdoc /> */
+ public char[] ReadCharArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadCharArray);
+ }
+
+ /** <inheritdoc /> */
+ public char[] ReadCharArray()
+ {
+ return Read(PortableUtils.ReadCharArray);
+ }
+
+ /** <inheritdoc /> */
+ public int ReadInt(string fieldName)
+ {
+ return ReadField(fieldName, ReadInt);
+ }
+
+ /** <inheritdoc /> */
+ public int ReadInt()
+ {
+ return Stream.ReadInt();
+ }
+
+ /** <inheritdoc /> */
+ public int[] ReadIntArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadIntArray);
+ }
+
+ /** <inheritdoc /> */
+ public int[] ReadIntArray()
+ {
+ return Read(PortableUtils.ReadIntArray);
+ }
+
+ /** <inheritdoc /> */
+ public long ReadLong(string fieldName)
+ {
+ return ReadField(fieldName, ReadLong);
+ }
+
+ /** <inheritdoc /> */
+ public long ReadLong()
+ {
+ return Stream.ReadLong();
+ }
+
+ /** <inheritdoc /> */
+ public long[] ReadLongArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadLongArray);
+ }
+
+ /** <inheritdoc /> */
+ public long[] ReadLongArray()
+ {
+ return Read(PortableUtils.ReadLongArray);
+ }
+
+ /** <inheritdoc /> */
+ public float ReadFloat(string fieldName)
+ {
+ return ReadField(fieldName, ReadFloat);
+ }
+
+ /** <inheritdoc /> */
+ public float ReadFloat()
+ {
+ return Stream.ReadFloat();
+ }
+
+ /** <inheritdoc /> */
+ public float[] ReadFloatArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadFloatArray);
+ }
+
+ /** <inheritdoc /> */
+ public float[] ReadFloatArray()
+ {
+ return Read(PortableUtils.ReadFloatArray);
+ }
+
+ /** <inheritdoc /> */
+ public double ReadDouble(string fieldName)
+ {
+ return ReadField(fieldName, ReadDouble);
+ }
+
+ /** <inheritdoc /> */
+ public double ReadDouble()
+ {
+ return Stream.ReadDouble();
+ }
+
+ /** <inheritdoc /> */
+ public double[] ReadDoubleArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadDoubleArray);
+ }
+
+ /** <inheritdoc /> */
+ public double[] ReadDoubleArray()
+ {
+ return Read(PortableUtils.ReadDoubleArray);
+ }
+
+ /** <inheritdoc /> */
+ public decimal ReadDecimal(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal ReadDecimal()
+ {
+ return Read(PortableUtils.ReadDecimal);
+ }
+
+ /** <inheritdoc /> */
+ public decimal[] ReadDecimalArray(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadDecimalArray);
+ }
+
+ /** <inheritdoc /> */
+ public decimal[] ReadDecimalArray()
+ {
+ return Read(PortableUtils.ReadDecimalArray);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate(string fieldName)
+ {
+ return ReadDate(fieldName, false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate(string fieldName, bool local)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadDate(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate()
+ {
+ return ReadDate(false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime? ReadDate(bool local)
+ {
+ return Read(r => PortableUtils.ReadDate(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray(string fieldName)
+ {
+ return ReadDateArray(fieldName, false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray(string fieldName, bool local)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadDateArray(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray()
+ {
+ return ReadDateArray(false);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime?[] ReadDateArray(bool local)
+ {
+ return Read(r => PortableUtils.ReadDateArray(r, local));
+ }
+
+ /** <inheritdoc /> */
+ public string ReadString(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadString);
+ }
+
+ /** <inheritdoc /> */
+ public string ReadString()
+ {
+ return Read(PortableUtils.ReadString);
+ }
+
+ /** <inheritdoc /> */
+ public string[] ReadStringArray(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<string>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public string[] ReadStringArray()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<string>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public Guid? ReadGuid(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid? ReadGuid()
+ {
+ return Read(PortableUtils.ReadGuid);
+ }
+
+ /** <inheritdoc /> */
+ public Guid?[] ReadGuidArray(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<Guid?>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public Guid?[] ReadGuidArray()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<Guid?>(r, false));
+ }
+
+ /** <inheritdoc /> */
+ public T ReadEnum<T>(string fieldName)
+ {
+ return ReadField(fieldName, PortableUtils.ReadEnum<T>);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadEnum<T>()
+ {
+ return Read(PortableUtils.ReadEnum<T>);
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadEnumArray<T>(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadEnumArray<T>()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public T ReadObject<T>(string fieldName)
+ {
+ if (_curRaw)
+ throw new PortableException("Cannot read named fields after raw data is read.");
+
+ int fieldId = PortableUtils.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+
+ if (SeekField(fieldId))
+ return Deserialize<T>();
+
+ return default(T);
+ }
+
+ /** <inheritdoc /> */
+ public T ReadObject<T>()
+ {
+ return Deserialize<T>();
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadObjectArray<T>(string fieldName)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public T[] ReadObjectArray<T>()
+ {
+ return Read(r => PortableUtils.ReadGenericArray<T>(r, true));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(string fieldName)
+ {
+ return ReadCollection(fieldName, null, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection()
+ {
+ return ReadCollection(null, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(string fieldName, PortableCollectionFactory factory,
+ PortableCollectionAdder adder)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadCollection(r, factory, adder));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection ReadCollection(PortableCollectionFactory factory,
+ PortableCollectionAdder adder)
+ {
+ return Read(r => PortableUtils.ReadCollection(r, factory, adder));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>(string fieldName)
+ {
+ return ReadGenericCollection<T>(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>()
+ {
+ return ReadGenericCollection((PortableGenericCollectionFactory<T>) null);
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>(string fieldName,
+ PortableGenericCollectionFactory<T> factory)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericCollection(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<T> ReadGenericCollection<T>(PortableGenericCollectionFactory<T> factory)
+ {
+ return Read(r => PortableUtils.ReadGenericCollection(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(string fieldName)
+ {
+ return ReadDictionary(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary()
+ {
+ return ReadDictionary((PortableDictionaryFactory)null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(string fieldName, PortableDictionaryFactory factory)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadDictionary(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary ReadDictionary(PortableDictionaryFactory factory)
+ {
+ return Read(r => PortableUtils.ReadDictionary(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(string fieldName)
+ {
+ return ReadGenericDictionary<TK, TV>(fieldName, null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>()
+ {
+ return ReadGenericDictionary((PortableGenericDictionaryFactory<TK, TV>) null);
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(string fieldName,
+ PortableGenericDictionaryFactory<TK, TV> factory)
+ {
+ return ReadField(fieldName, r => PortableUtils.ReadGenericDictionary(r, factory));
+ }
+
+ /** <inheritdoc /> */
+ public IDictionary<TK, TV> ReadGenericDictionary<TK, TV>(PortableGenericDictionaryFactory<TK, TV> factory)
+ {
+ return Read(r => PortableUtils.ReadGenericDictionary(r, factory));
+ }
+
+ /// <summary>
+ /// Enable detach mode for the next object read.
+ /// </summary>
+ public void DetachNext()
+ {
+ _detach = true;
+ }
+
+ /// <summary>
+ /// Deserialize object.
+ /// </summary>
+ /// <returns>Deserialized object.</returns>
+ public T Deserialize<T>()
+ {
+ int pos = Stream.Position;
+
+ byte hdr = Stream.ReadByte();
+
+ var doDetach = _detach; // save detach flag into a var and reset so it does not go deeper
+
+ _detach = false;
+
+ switch (hdr)
+ {
+ case PortableUtils.HdrNull:
+ return default(T);
+
+ case PortableUtils.HdrHnd:
+ return ReadHandleObject<T>(pos);
+
+ case PortableUtils.HdrFull:
+ return ReadFullObject<T>(pos);
+
+ case PortableUtils.TypePortable:
+ return ReadPortableObject<T>(doDetach);
+ }
+
+ if (PortableUtils.IsPredefinedType(hdr))
+ return PortableSystemHandlers.ReadSystemType<T>(hdr, this);
+
+ throw new PortableException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']');
+ }
+
+ /// <summary>
+ /// Reads the portable object.
+ /// </summary>
+ private T ReadPortableObject<T>(bool doDetach)
+ {
+ var len = Stream.ReadInt();
+
+ var portablePos = Stream.Position;
+
+ if (_mode != PortableMode.Deserialize)
+ return TypeCaster<T>.Cast(ReadAsPortable(portablePos, len, doDetach));
+
+ Stream.Seek(len, SeekOrigin.Current);
+
+ var offset = Stream.ReadInt();
+
+ var retPos = Stream.Position;
+
+ Stream.Seek(portablePos + offset, SeekOrigin.Begin);
+
+ _mode = PortableMode.KeepPortable;
+
+ try
+ {
+ return Deserialize<T>();
+ }
+ finally
+ {
+ _mode = PortableMode.Deserialize;
+
+ Stream.Seek(retPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the portable object in portable form.
+ /// </summary>
+ private PortableUserObject ReadAsPortable(int dataPos, int dataLen, bool doDetach)
+ {
+ try
+ {
+ Stream.Seek(dataLen + dataPos, SeekOrigin.Begin);
+
+ var offs = Stream.ReadInt(); // offset inside data
+
+ var pos = dataPos + offs;
+
+ if (!doDetach)
+ return GetPortableUserObject(pos, pos, Stream.Array());
+
+ Stream.Seek(pos + 10, SeekOrigin.Begin);
+
+ var len = Stream.ReadInt();
+
+ Stream.Seek(pos, SeekOrigin.Begin);
+
+ return GetPortableUserObject(pos, 0, Stream.ReadByteArray(len));
+ }
+ finally
+ {
+ Stream.Seek(dataPos + dataLen + 4, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the full object.
+ /// </summary>
+ [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "hashCode")]
+ private T ReadFullObject<T>(int pos)
+ {
+ // Read header.
+ bool userType = Stream.ReadBool();
+ int typeId = Stream.ReadInt();
+ // ReSharper disable once UnusedVariable
+ int hashCode = Stream.ReadInt();
+ int len = Stream.ReadInt();
+ int rawOffset = Stream.ReadInt();
+
+ try
+ {
+ // Already read this object?
+ object hndObj;
+
+ if (_hnds != null && _hnds.TryGetValue(pos, out hndObj))
+ return (T) hndObj;
+
+ if (userType && _mode == PortableMode.ForcePortable)
+ {
+ PortableUserObject portObj;
+
+ if (_detach)
+ {
+ Stream.Seek(pos, SeekOrigin.Begin);
+
+ portObj = GetPortableUserObject(pos, 0, Stream.ReadByteArray(len));
+ }
+ else
+ portObj = GetPortableUserObject(pos, pos, Stream.Array());
+
+ T obj = _builder == null ? TypeCaster<T>.Cast(portObj) : TypeCaster<T>.Cast(_builder.Child(portObj));
+
+ AddHandle(pos, obj);
+
+ return obj;
+ }
+ else
+ {
+ // Find descriptor.
+ IPortableTypeDescriptor desc;
+
+ if (!_descs.TryGetValue(PortableUtils.TypeKey(userType, typeId), out desc))
+ throw new PortableException("Unknown type ID: " + typeId);
+
+ // Instantiate object.
+ if (desc.Type == null)
+ throw new PortableException("No matching type found for object [typeId=" +
+ desc.TypeId + ", typeName=" + desc.TypeName + ']');
+
+ // Preserve old frame.
+ int oldTypeId = _curTypeId;
+ int oldPos = _curPos;
+ int oldRawOffset = _curRawOffset;
+ IPortableNameMapper oldConverter = _curConverter;
+ IPortableIdMapper oldMapper = _curMapper;
+ bool oldRaw = _curRaw;
+
+ // Set new frame.
+ _curTypeId = typeId;
+ _curPos = pos;
+ _curRawOffset = rawOffset;
+ _curConverter = desc.NameConverter;
+ _curMapper = desc.Mapper;
+ _curRaw = false;
+
+ // Read object.
+ object obj;
+
+ var sysSerializer = desc.Serializer as IPortableSystemTypeSerializer;
+
+ if (sysSerializer != null)
+ obj = sysSerializer.ReadInstance(this);
+ else
+ {
+ try
+ {
+ obj = FormatterServices.GetUninitializedObject(desc.Type);
+
+ // Save handle.
+ AddHandle(pos, obj);
+ }
+ catch (Exception e)
+ {
+ throw new PortableException("Failed to create type instance: " +
+ desc.Type.AssemblyQualifiedName, e);
+ }
+
+ desc.Serializer.ReadPortable(obj, this);
+ }
+
+ // Restore old frame.
+ _curTypeId = oldTypeId;
+ _curPos = oldPos;
+ _curRawOffset = oldRawOffset;
+ _curConverter = oldConverter;
+ _curMapper = oldMapper;
+ _curRaw = oldRaw;
+
+ var wrappedSerializable = obj as SerializableObjectHolder;
+
+ return wrappedSerializable != null ? (T) wrappedSerializable.Item : (T) obj;
+ }
+ }
+ finally
+ {
+ // Advance stream pointer.
+ Stream.Seek(pos + len, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Reads the handle object.
+ /// </summary>
+ private T ReadHandleObject<T>(int pos)
+ {
+ // Get handle position.
+ int hndPos = pos - Stream.ReadInt();
+
+ int retPos = Stream.Position;
+
+ try
+ {
+ object hndObj;
+
+ if (_builder == null || !_builder.CachedField(hndPos, out hndObj))
+ {
+ if (_hnds == null || !_hnds.TryGetValue(hndPos, out hndObj))
+ {
+ // No such handler, i.e. we trying to deserialize inner object before deserializing outer.
+ Stream.Seek(hndPos, SeekOrigin.Begin);
+
+ hndObj = Deserialize<T>();
+ }
+
+ // Notify builder that we deserialized object on other location.
+ if (_builder != null)
+ _builder.CacheField(hndPos, hndObj);
+ }
+
+ return (T) hndObj;
+ }
+ finally
+ {
+ // Position stream to correct place.
+ Stream.Seek(retPos, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Adds a handle to the dictionary.
+ /// </summary>
+ /// <param name="pos">Position.</param>
+ /// <param name="obj">Object.</param>
+ private void AddHandle(int pos, object obj)
+ {
+ if (_hnds == null)
+ _hnds = new PortableReaderHandleDictionary(pos, obj);
+ else
+ _hnds.Add(pos, obj);
+ }
+
+ /// <summary>
+ /// Underlying stream.
+ /// </summary>
+ public IPortableStream Stream
+ {
+ get;
+ private set;
+ }
+
+ /// <summary>
+ /// Mark current output as raw.
+ /// </summary>
+ private void MarkRaw()
+ {
+ if (!_curRaw)
+ {
+ _curRaw = true;
+
+ Stream.Seek(_curPos + _curRawOffset, SeekOrigin.Begin);
+ }
+ }
+
+ /// <summary>
+ /// Seek field with the given ID in the current object.
+ /// </summary>
+ /// <param name="fieldId">Field ID.</param>
+ /// <returns>True in case the field was found and position adjusted, false otherwise.</returns>
+ private bool SeekField(int fieldId)
+ {
+ // This method is expected to be called when stream pointer is set either before
+ // the field or on raw data offset.
+ int start = _curPos + 18;
+ int end = _curPos + _curRawOffset;
+
+ int initial = Stream.Position;
+
+ int cur = initial;
+
+ while (cur < end)
+ {
+ int id = Stream.ReadInt();
+
+ if (fieldId == id)
+ {
+ // Field is found, return.
+ Stream.Seek(4, SeekOrigin.Current);
+
+ return true;
+ }
+
+ Stream.Seek(Stream.ReadInt(), SeekOrigin.Current);
+
+ cur = Stream.Position;
+ }
+
+ Stream.Seek(start, SeekOrigin.Begin);
+
+ cur = start;
+
+ while (cur < initial)
+ {
+ int id = Stream.ReadInt();
+
+ if (fieldId == id)
+ {
+ // Field is found, return.
+ Stream.Seek(4, SeekOrigin.Current);
+
+ return true;
+ }
+
+ Stream.Seek(Stream.ReadInt(), SeekOrigin.Current);
+
+ cur = Stream.Position;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Determines whether header at current position is HDR_NULL.
+ /// </summary>
+ private bool IsNullHeader()
+ {
+ var hdr = ReadByte();
+
+ return hdr != PortableUtils.HdrNull;
+ }
+
+ /// <summary>
+ /// Seeks the field by name, reads header and returns true if field is present and header is not null.
+ /// </summary>
+ private bool SeekField(string fieldName)
+ {
+ if (_curRaw)
+ throw new PortableException("Cannot read named fields after raw data is read.");
+
+ var fieldId = PortableUtils.FieldId(_curTypeId, fieldName, _curConverter, _curMapper);
+
+ if (!SeekField(fieldId))
+ return false;
+
+ return IsNullHeader();
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<IPortableStream, T> readFunc)
+ {
+ return SeekField(fieldName) ? readFunc(Stream) : default(T);
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<PortableReaderImpl, T> readFunc)
+ {
+ return SeekField(fieldName) ? readFunc(this) : default(T);
+ }
+
+ /// <summary>
+ /// Seeks specified field and invokes provided func.
+ /// </summary>
+ private T ReadField<T>(string fieldName, Func<T> readFunc)
+ {
+ return SeekField(fieldName) ? readFunc() : default(T);
+ }
+
+ /// <summary>
+ /// Reads header and invokes specified func if the header is not null.
+ /// </summary>
+ private T Read<T>(Func<PortableReaderImpl, T> readFunc)
+ {
+ return IsNullHeader() ? readFunc(this) : default(T);
+ }
+
+ /// <summary>
+ /// Reads header and invokes specified func if the header is not null.
+ /// </summary>
+ private T Read<T>(Func<IPortableStream, T> readFunc)
+ {
+ return IsNullHeader() ? readFunc(Stream) : default(T);
+ }
+
+ /// <summary>
+ /// Gets the portable user object from a byte array.
+ /// </summary>
+ /// <param name="pos">Position in the current stream.</param>
+ /// <param name="offs">Offset in the byte array.</param>
+ /// <param name="bytes">Bytes.</param>
+ private PortableUserObject GetPortableUserObject(int pos, int offs, byte[] bytes)
+ {
+ Stream.Seek(pos + 2, SeekOrigin.Begin);
+
+ var id = Stream.ReadInt();
+
+ var hash = Stream.ReadInt();
+
+ return new PortableUserObject(_marsh, bytes, offs, id, hash);
+ }
+ }
+}