Repository: ignite Updated Branches: refs/heads/master d38ca8b10 -> b5c7b6f5e
http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs index 841972d..7ab69e9 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs @@ -65,6 +65,14 @@ namespace Apache.Ignite.Core.Binary int EnumValue { get; } /// <summary> + /// Gets the name of the underlying enum value. + /// </summary> + /// <value> + /// The name of the enum value. + /// </value> + string EnumName { get; } + + /// <summary> /// Creates a new <see cref="IBinaryObjectBuilder"/> based on this object. /// <para /> /// This is equivalent to <see cref="IBinary.GetBuilder(IBinaryObject)"/>. http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs index bec863f..df6693d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs @@ -61,5 +61,11 @@ namespace Apache.Ignite.Core.Binary /// Gets the type identifier. /// </summary> int TypeId { get; } + + /// <summary> + /// Gets the enum values. + /// Only valid when <see cref="IsEnum"/> is true. + /// </summary> + IEnumerable<IBinaryObject> GetEnumValues(); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs index 4f3156c..bcf6c2d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs @@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Binary { using System; using System.Collections.Generic; + using System.Diagnostics; using System.IO; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Common; @@ -165,7 +166,8 @@ namespace Apache.Ignite.Core.Impl.Binary public IBinaryObject BuildEnum(Type type, int value) { IgniteArgumentCheck.NotNull(type, "type"); - IgniteArgumentCheck.Ensure(type.IsEnum, "type", "Type should be an Enum."); + IgniteArgumentCheck.Ensure(BinaryUtils.IsIgniteEnum(type), "type", + "Type should be an Enum."); var desc = Marshaller.GetDescriptor(type); @@ -176,15 +178,53 @@ namespace Apache.Ignite.Core.Impl.Binary return new BinaryEnum(desc.TypeId, value, Marshaller); } + /** <inheritDoc /> */ + public IBinaryObject BuildEnum(string typeName, string valueName) + { + IgniteArgumentCheck.NotNullOrEmpty(typeName, "typeName"); + IgniteArgumentCheck.NotNullOrEmpty(valueName, "valueName"); + + var desc = Marshaller.GetDescriptor(typeName); + + IgniteArgumentCheck.Ensure(desc.IsEnum, "typeName", "Type should be an Enum."); + + _marsh.PutBinaryType(desc); + + var value = GetEnumValueAsInt(typeName, valueName, desc); + + return new BinaryEnum(desc.TypeId, value, Marshaller); + } + + /** <inheritDoc /> */ + public IBinaryObject BuildEnum(Type type, string valueName) + { + IgniteArgumentCheck.NotNullOrEmpty(valueName, "valueName"); + + var desc = Marshaller.GetDescriptor(type); + + IgniteArgumentCheck.Ensure(desc.IsEnum, "typeName", "Type should be an Enum."); + + _marsh.PutBinaryType(desc); + + var value = GetEnumValueAsInt(type.ToString(), valueName, desc); + + return new BinaryEnum(desc.TypeId, value, Marshaller); + } + + /** <inheritDoc /> */ + public IBinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values) + { + IgniteArgumentCheck.NotNullOrEmpty(typeName, "typeName"); + + return Marshaller.Ignite.BinaryProcessor.RegisterEnum(typeName, values); + } + /// <summary> /// Marshaller. /// </summary> internal Marshaller Marshaller { - get - { - return _marsh; - } + get { return _marsh; } } /// <summary> @@ -199,5 +239,22 @@ namespace Apache.Ignite.Core.Impl.Binary { return new BinaryObjectBuilder(this, parent, obj, desc); } + + /// <summary> + /// Gets the enum value as int. + /// </summary> + private int GetEnumValueAsInt(string typeName, string valueName, IBinaryTypeDescriptor desc) + { + var type = Marshaller.GetBinaryType(desc.TypeId); + + var value = type.GetEnumValue(valueName); + + IgniteArgumentCheck.Ensure(value != null, "valueName", + string.Format("Enum '{0}' does not have a value {1}", typeName, valueName)); + + Debug.Assert(value.HasValue); + + return value.Value; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs index 710cf17..2bc4bdf 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs @@ -88,6 +88,12 @@ namespace Apache.Ignite.Core.Impl.Binary } /** <inheritdoc /> */ + public string EnumName + { + get { return _marsh.GetBinaryType(_typeId).GetEnumName(_enumValue); } + } + + /** <inheritdoc /> */ public IBinaryObjectBuilder ToBuilder() { throw new NotSupportedException("Builder cannot be created for enum."); @@ -136,11 +142,8 @@ namespace Apache.Ignite.Core.Impl.Binary return string.Format("BinaryEnum [typeId={0}, enumValue={1}]", _typeId, _enumValue); } - var desc = _marsh.GetDescriptor(true, _typeId); - var enumValueName = desc != null && desc.Type != null ? Enum.GetName(desc.Type, _enumValue) : null; - return string.Format("{0} [typeId={1}, enumValue={2}, enumValueName={3}]", - meta.TypeName, _typeId, _enumValue, enumValueName); + meta.TypeName, _typeId, _enumValue, EnumName); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs index 480e0e6..8c5cee6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs @@ -131,7 +131,18 @@ namespace Apache.Ignite.Core.Impl.Binary { get { - throw new NotSupportedException("IBinaryObject.Value is only supported for enums. " + + throw new NotSupportedException("IBinaryObject.EnumValue is only supported for enums. " + + "Check IBinaryObject.GetBinaryType().IsEnum property before accessing Value."); + } + } + + /** <inheritdoc /> */ + [ExcludeFromCodeCoverage] + public string EnumName + { + get + { + throw new NotSupportedException("IBinaryObject.EnumName is only supported for enums. " + "Check IBinaryObject.GetBinaryType().IsEnum property before accessing Value."); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs index 72a1d5b..f48bcc0 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs @@ -24,7 +24,7 @@ namespace Apache.Ignite.Core.Impl.Binary using Apache.Ignite.Core.Impl.Unmanaged; /// <summary> - /// Binary metadata processor. + /// Binary metadata processor, delegates to PlatformBinaryProcessor in Java. /// </summary> internal class BinaryProcessor : PlatformTarget { @@ -38,7 +38,8 @@ namespace Apache.Ignite.Core.Impl.Binary PutMeta = 3, GetSchema = 4, RegisterType = 5, - GetType = 6 + GetType = 6, + RegisterEnum = 7 } /// <summary> @@ -54,9 +55,9 @@ namespace Apache.Ignite.Core.Impl.Binary /// <summary> /// Gets metadata for specified type. /// </summary> - public IBinaryType GetBinaryType(int typeId) + public BinaryType GetBinaryType(int typeId) { - return DoOutInOp<IBinaryType>((int) Op.GetMeta, + return DoOutInOp((int) Op.GetMeta, writer => writer.WriteInt(typeId), stream => { @@ -126,8 +127,27 @@ namespace Apache.Ignite.Core.Impl.Binary w.WriteInt(field.Value.FieldId); } + // Enum data w.WriteBoolean(meta.IsEnum); + if (meta.IsEnum) + { + if (meta.EnumValuesMap != null) + { + w.WriteInt(meta.EnumValuesMap.Count); + + foreach (var pair in meta.EnumValuesMap) + { + w.WriteString(pair.Key); + w.WriteInt(pair.Value); + } + } + else + { + w.WriteInt(0); + } + } + // Send schemas var desc = meta.Descriptor; Debug.Assert(desc != null); @@ -175,6 +195,43 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Registers the enum. + /// </summary> + /// <param name="typeName">Name of the type.</param> + /// <param name="values">The values.</param> + /// <returns>Resulting binary type.</returns> + public BinaryType RegisterEnum(string typeName, IEnumerable<KeyValuePair<string, int>> values) + { + Debug.Assert(typeName != null); + + return DoOutInOp((int) Op.RegisterEnum, w => + { + w.WriteString(typeName); + + if (values == null) + { + w.WriteInt(0); + } + else + { + var countPos = w.Stream.Position; + w.WriteInt(0); + var count = 0; + + foreach (var enumPair in values) + { + w.WriteString(enumPair.Key); + w.WriteInt(enumPair.Value); + + count++; + } + + w.Stream.WriteInt(countPos, count); + } + }, s => s.ReadBool() ? new BinaryType(Marshaller.StartUnmarshal(s)) : null); + } + + /// <summary> /// Gets the type by id. /// </summary> /// <param name="id">The identifier.</param> http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs index a5c6814..73a0456 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs @@ -401,6 +401,7 @@ namespace Apache.Ignite.Core.Impl.Binary return default(T); case BinaryUtils.TypeEnum: + case BinaryUtils.TypeBinaryEnum: // Never read enums in binary mode when reading a field (we do not support half-binary objects) return ReadEnum0<T>(this, false); @@ -411,9 +412,9 @@ namespace Apache.Ignite.Core.Impl.Binary return ReadObject<T>(); default: - throw new BinaryObjectException( - string.Format("Invalid header on enum deserialization. Expected: {0} or {1} but was: {2}", - BinaryUtils.TypeEnum, BinaryUtils.HdrFull, hdr)); + throw new BinaryObjectException(string.Format( + "Invalid header on enum deserialization. Expected: {0} or {1} or {2} but was: {3}", + BinaryUtils.TypeEnum, BinaryUtils.TypeBinaryEnum, BinaryUtils.HdrFull, hdr)); } } @@ -571,6 +572,7 @@ namespace Apache.Ignite.Core.Impl.Binary return true; case BinaryUtils.TypeEnum: + case BinaryUtils.TypeBinaryEnum: res = ReadEnum0<T>(this, _mode != BinaryMode.Deserialize); return true; @@ -994,7 +996,9 @@ namespace Apache.Ignite.Core.Impl.Binary var enumValue = reader.ReadInt(); if (!keepBinary) + { return BinaryUtils.GetEnumValue<T>(enumValue, enumType, reader.Marshaller); + } return TypeCaster<T>.Cast(new BinaryEnum(enumType, enumValue, reader.Marshaller)); } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs index 1dfc3b6..95a0be3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs @@ -255,7 +255,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (elemType == typeof(Guid?)) return new BinarySystemWriteHandler<Guid?[]>(WriteGuidArray, true); // Enums. - if (IsIntEnum(elemType) || elemType == typeof(BinaryEnum)) + if (BinaryUtils.IsIgniteEnum(elemType) || elemType == typeof(BinaryEnum)) return new BinarySystemWriteHandler<object>(WriteEnumArray, true); // Object array. @@ -266,23 +266,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Determines whether specified type is an enum which fits into Int32. - /// </summary> - private static bool IsIntEnum(Type type) - { - if (!type.IsEnum) - return false; - - var underlyingType = Enum.GetUnderlyingType(type); - - return underlyingType == typeof(int) - || underlyingType == typeof(short) - || underlyingType == typeof(ushort) - || underlyingType == typeof(byte) - || underlyingType == typeof(sbyte); - } - - /// <summary> /// Find write handler for type. /// </summary> /// <param name="type">Type.</param> @@ -294,10 +277,10 @@ namespace Apache.Ignite.Core.Impl.Binary if (TypeIds.TryGetValue(type, out res)) return res; - if (type.IsEnum) + if (BinaryUtils.IsIgniteEnum(type)) return BinaryUtils.TypeEnum; - if (type.IsArray && type.GetElementType().IsEnum) + if (type.IsArray && BinaryUtils.IsIgniteEnum(type.GetElementType())) return BinaryUtils.TypeArrayEnum; return BinaryUtils.TypeObject; @@ -545,7 +528,7 @@ namespace Apache.Ignite.Core.Impl.Binary { var binEnum = obj; - ctx.Stream.WriteByte(BinaryUtils.TypeEnum); + ctx.Stream.WriteByte(BinaryUtils.TypeBinaryEnum); ctx.WriteInt(binEnum.TypeId); ctx.WriteInt(binEnum.EnumValue); http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs index a2783ba..2ac617e 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -143,6 +143,9 @@ namespace Apache.Ignite.Core.Impl.Binary /** Type: enum array. */ public const byte TypeArrayEnum = 29; + /** Type: binary enum. */ + public const byte TypeBinaryEnum = 38; + /** Type: native job holder. */ public const byte TypeNativeJobHolder = 77; @@ -1778,6 +1781,22 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Determines whether specified type is Ignite-compatible enum (value fits into 4 bytes). + /// </summary> + public static bool IsIgniteEnum(Type type) + { + Debug.Assert(type != null); + + if (!type.IsEnum) + return false; + + var enumType = Enum.GetUnderlyingType(type); + + return enumType == typeof(int) || enumType == typeof(byte) || enumType == typeof(sbyte) + || enumType == typeof(short) || enumType == typeof(ushort) || enumType == typeof(uint); + } + + /// <summary> /// Creates and instance from the type name in reader. /// </summary> private static T CreateInstance<T>(BinaryReader reader) http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs index 56774d4..a5fed48 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs @@ -1468,7 +1468,7 @@ namespace Apache.Ignite.Core.Impl.Binary { _metas = new Dictionary<int, BinaryType>(1) { - {desc.TypeId, new BinaryType(desc, fields)} + {desc.TypeId, new BinaryType(desc, _marsh, fields)} }; } else @@ -1478,7 +1478,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (_metas.TryGetValue(desc.TypeId, out meta)) meta.UpdateFields(fields); else - _metas[desc.TypeId] = new BinaryType(desc, fields); + _metas[desc.TypeId] = new BinaryType(desc, _marsh, fields); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs index ea2964a..8f12acf 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -97,13 +97,13 @@ namespace Apache.Ignite.Core.Impl.Binary if (typeCfgs != null) foreach (BinaryTypeConfiguration typeCfg in typeCfgs) - AddUserType(cfg, typeCfg, typeResolver); + AddUserType(typeCfg, typeResolver); var typeNames = _cfg.Types; if (typeNames != null) foreach (string typeName in typeNames) - AddUserType(cfg, new BinaryTypeConfiguration(typeName), typeResolver); + AddUserType(new BinaryTypeConfiguration(typeName), typeResolver); } /// <summary> @@ -289,14 +289,16 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="typeId">Type ID.</param> /// <returns>Metadata or null.</returns> - public IBinaryType GetBinaryType(int typeId) + public BinaryType GetBinaryType(int typeId) { if (Ignite != null) { - IBinaryType meta = Ignite.BinaryProcessor.GetBinaryType(typeId); + var meta = Ignite.BinaryProcessor.GetBinaryType(typeId); if (meta != null) + { return meta; + } } return BinaryType.Empty; @@ -314,7 +316,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (Ignite != null) { - ICollection<BinaryType> metas = new[] {new BinaryType(desc)}; + ICollection<BinaryType> metas = new[] {new BinaryType(desc, this)}; Ignite.BinaryProcessor.PutBinaryTypes(metas); } } @@ -337,7 +339,8 @@ namespace Apache.Ignite.Core.Impl.Binary IDictionary<int, BinaryTypeHolder> metas0 = new Dictionary<int, BinaryTypeHolder>(_metas); - holder = new BinaryTypeHolder(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, desc.IsEnum); + holder = new BinaryTypeHolder(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, + desc.IsEnum, this); metas0[desc.TypeId] = holder; @@ -366,16 +369,7 @@ namespace Apache.Ignite.Core.Impl.Binary { foreach (var meta in newMetas) { - var mergeInfo = new Dictionary<int, Tuple<string, BinaryField>>(meta.GetFieldsMap().Count); - - foreach (var fieldMeta in meta.GetFieldsMap()) - { - int fieldId = BinaryUtils.FieldId(meta.TypeId, fieldMeta.Key, null, null); - - mergeInfo[fieldId] = new Tuple<string, BinaryField>(fieldMeta.Key, fieldMeta.Value); - } - - _metas[meta.TypeId].Merge(mergeInfo); + _metas[meta.TypeId].Merge(meta); } } @@ -391,7 +385,9 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryFullTypeDescriptor desc; if (!_typeToDesc.TryGetValue(type, out desc) || !desc.IsRegistered) + { desc = RegisterType(type, desc); + } return desc; } @@ -405,10 +401,14 @@ namespace Apache.Ignite.Core.Impl.Binary { BinaryFullTypeDescriptor desc; - return _typeNameToDesc.TryGetValue(typeName, out desc) - ? (IBinaryTypeDescriptor) desc - : new BinarySurrogateTypeDescriptor(_cfg, - GetTypeId(typeName, _cfg.IdMapper), typeName); + if (_typeNameToDesc.TryGetValue(typeName, out desc)) + { + return desc; + } + + var typeId = GetTypeId(typeName, _cfg.IdMapper); + + return GetDescriptor(true, typeId, typeName: typeName); } /// <summary> @@ -416,18 +416,18 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="userType">User type flag.</param> /// <param name="typeId">Type id.</param> - /// <param name="requiresType"> - /// If set to true, resulting descriptor must have Type property populated. + /// <param name="requiresType">If set to true, resulting descriptor must have Type property populated. /// <para /> /// When working in binary mode, we don't need Type. And there is no Type at all in some cases. /// So we should not attempt to call BinaryProcessor right away. /// Only when we really deserialize the value, requiresType is set to true - /// and we attempt to resolve the type by all means. - /// </param> + /// and we attempt to resolve the type by all means.</param> + /// <param name="typeName">Known type name.</param> /// <returns> /// Descriptor. /// </returns> - public IBinaryTypeDescriptor GetDescriptor(bool userType, int typeId, bool requiresType = false) + public IBinaryTypeDescriptor GetDescriptor(bool userType, int typeId, bool requiresType = false, + string typeName = null) { BinaryFullTypeDescriptor desc; @@ -442,7 +442,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (requiresType && _ignite != null) { // Check marshaller context for dynamically registered type. - var typeName = _ignite.BinaryProcessor.GetTypeName(typeId); + typeName = typeName ?? _ignite.BinaryProcessor.GetTypeName(typeId); if (typeName != null) { @@ -460,15 +460,16 @@ namespace Apache.Ignite.Core.Impl.Binary if (meta != BinaryType.Empty) { - desc = new BinaryFullTypeDescriptor(null, meta.TypeId, meta.TypeName, true, null, null, null, false, - meta.AffinityKeyFieldName, meta.IsEnum); - - _idToDesc.GetOrAdd(typeKey, _ => desc); + var typeCfg = new BinaryTypeConfiguration(meta.TypeName) + { + IsEnum = meta.IsEnum, + AffinityKeyFieldName = meta.AffinityKeyFieldName + }; - return desc; + return AddUserType(typeCfg, new TypeResolver()); } - return new BinarySurrogateTypeDescriptor(_cfg, typeId, null); + return new BinarySurrogateTypeDescriptor(_cfg, typeId, typeName); } /// <summary> @@ -507,7 +508,7 @@ namespace Apache.Ignite.Core.Impl.Binary desc = desc == null ? new BinaryFullTypeDescriptor(type, typeId, typeName, true, _cfg.NameMapper, - _cfg.IdMapper, ser, false, null, type.IsEnum, registered) + _cfg.IdMapper, ser, false, null, BinaryUtils.IsIgniteEnum(type), registered) : new BinaryFullTypeDescriptor(desc, type, ser, registered); if (RegistrationDisabled) @@ -540,11 +541,10 @@ namespace Apache.Ignite.Core.Impl.Binary /// <summary> /// Add user type. /// </summary> - /// <param name="cfg">The binary configuration.</param> /// <param name="typeCfg">Type configuration.</param> /// <param name="typeResolver">The type resolver.</param> /// <exception cref="BinaryObjectException"></exception> - private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, TypeResolver typeResolver) + private BinaryFullTypeDescriptor AddUserType(BinaryTypeConfiguration typeCfg, TypeResolver typeResolver) { // Get converter/mapper/serializer. IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? _cfg.NameMapper ?? GetDefaultNameMapper(); @@ -560,23 +560,23 @@ namespace Apache.Ignite.Core.Impl.Binary { ValidateUserType(type); - if (typeCfg.IsEnum != type.IsEnum) + if (typeCfg.IsEnum != BinaryUtils.IsIgniteEnum(type)) { throw new BinaryObjectException( string.Format( "Invalid IsEnum flag in binary type configuration. " + - "Configuration value: IsEnum={0}, actual type: IsEnum={1}", - typeCfg.IsEnum, type.IsEnum)); + "Configuration value: IsEnum={0}, actual type: IsEnum={1}, type={2}", + typeCfg.IsEnum, type.IsEnum, type)); } // Type is found. var typeName = GetTypeName(type, nameMapper); int typeId = GetTypeId(typeName, idMapper); var affKeyFld = typeCfg.AffinityKeyFieldName ?? GetAffinityKeyFieldNameFromAttribute(type); - var serializer = GetSerializer(cfg, typeCfg, type, typeId, nameMapper, idMapper, _log); + var serializer = GetSerializer(_cfg, typeCfg, type, typeId, nameMapper, idMapper, _log); - AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, - affKeyFld, type.IsEnum); + return AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, + affKeyFld, BinaryUtils.IsIgniteEnum(type)); } else { @@ -585,7 +585,7 @@ namespace Apache.Ignite.Core.Impl.Binary int typeId = GetTypeId(typeName, idMapper); - AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, + return AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, typeCfg.AffinityKeyFieldName, typeCfg.IsEnum); } } @@ -653,7 +653,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="serializer">Serializer.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> - private void AddType(Type type, int typeId, string typeName, bool userType, + private BinaryFullTypeDescriptor AddType(Type type, int typeId, string typeName, bool userType, bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum) { @@ -685,6 +685,8 @@ namespace Apache.Ignite.Core.Impl.Binary _typeNameToDesc.GetOrAdd(typeName, x => descriptor); _idToDesc.GetOrAdd(typeKey, _ => descriptor); + + return descriptor; } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs index 837c28a..db54ce7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs @@ -17,9 +17,11 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata { + using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; + using System.Linq; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Impl.Common; @@ -30,7 +32,7 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata { /** Empty metadata. */ public static readonly BinaryType Empty = - new BinaryType(BinaryUtils.TypeObject, BinaryTypeNames.TypeNameObject, null, null, false); + new BinaryType(BinaryUtils.TypeObject, BinaryTypeNames.TypeNameObject, null, null, false, null, null); /** Empty dictionary. */ private static readonly IDictionary<string, BinaryField> EmptyDict = new Dictionary<string, BinaryField>(); @@ -44,6 +46,12 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /** Fields. */ private readonly IDictionary<string, BinaryField> _fields; + /** Enum values. */ + private readonly IDictionary<string, int> _enumNameToValue; + + /** Enum names. */ + private readonly IDictionary<int, string> _enumValueToName; + /** Enum flag. */ private readonly bool _isEnum; @@ -59,6 +67,9 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /** Type descriptor. */ private readonly IBinaryTypeDescriptor _descriptor; + /** Marshaller. */ + private readonly Marshaller _marshaller; + /// <summary> /// Initializes the <see cref="BinaryType"/> class. /// </summary> @@ -117,7 +128,7 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /// Initializes a new instance of the <see cref="BinaryType" /> class. /// </summary> /// <param name="reader">The reader.</param> - public BinaryType(IBinaryRawReader reader) + public BinaryType(BinaryReader reader) { _typeId = reader.ReadInt(); _typeName = reader.ReadString(); @@ -136,15 +147,34 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata } _isEnum = reader.ReadBoolean(); + + if (_isEnum) + { + var count = reader.ReadInt(); + + _enumNameToValue = new Dictionary<string, int>(count); + + for (var i = 0; i < count; i++) + { + _enumNameToValue[reader.ReadString()] = reader.ReadInt(); + } + + _enumValueToName = _enumNameToValue.ToDictionary(x => x.Value, x => x.Key); + } + + _marshaller = reader.Marshaller; } /// <summary> - /// Initializes a new instance of the <see cref="BinaryType"/> class. + /// Initializes a new instance of the <see cref="BinaryType" /> class. /// </summary> /// <param name="desc">Descriptor.</param> + /// <param name="marshaller">Marshaller.</param> /// <param name="fields">Fields.</param> - public BinaryType(IBinaryTypeDescriptor desc, IDictionary<string, BinaryField> fields = null) - : this (desc.TypeId, desc.TypeName, fields, desc.AffinityKeyFieldName, desc.IsEnum) + public BinaryType(IBinaryTypeDescriptor desc, Marshaller marshaller, + IDictionary<string, BinaryField> fields = null) + : this (desc.TypeId, desc.TypeName, fields, desc.AffinityKeyFieldName, desc.IsEnum, + GetEnumValues(desc), marshaller) { _descriptor = desc; } @@ -157,14 +187,24 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /// <param name="fields">Fields.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> + /// <param name="enumValues">Enum values.</param> + /// <param name="marshaller">Marshaller.</param> public BinaryType(int typeId, string typeName, IDictionary<string, BinaryField> fields, - string affKeyFieldName, bool isEnum) + string affKeyFieldName, bool isEnum, IDictionary<string, int> enumValues, Marshaller marshaller) { _typeId = typeId; _typeName = typeName; _affinityKeyFieldName = affKeyFieldName; _fields = fields; _isEnum = isEnum; + _enumNameToValue = enumValues; + + if (_enumNameToValue != null) + { + _enumValueToName = _enumNameToValue.ToDictionary(x => x.Value, x => x.Key); + } + + _marshaller = marshaller; } /// <summary> @@ -232,6 +272,27 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata get { return _isEnum; } } + /** <inheritdoc /> */ + public IEnumerable<IBinaryObject> GetEnumValues() + { + if (!_isEnum) + { + throw new NotSupportedException( + "IBinaryObject.Value is only supported for enums. " + + "Check IBinaryObject.GetBinaryType().IsEnum property before accessing Value."); + } + + if (_marshaller == null) + { + yield break; + } + + foreach (var pair in _enumValueToName) + { + yield return new BinaryEnum(_typeId, pair.Key, _marshaller); + } + } + /// <summary> /// Gets the descriptor. /// </summary> @@ -250,6 +311,14 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata } /// <summary> + /// Gets the enum values map. + /// </summary> + public IDictionary<string, int> EnumValuesMap + { + get { return _enumNameToValue; } + } + + /// <summary> /// Updates the fields. /// </summary> public void UpdateFields(IDictionary<string, BinaryField> fields) @@ -262,5 +331,103 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata foreach (var field in fields) _fields[field.Key] = field.Value; } + + /// <summary> + /// Gets the enum value by name. + /// </summary> + public int? GetEnumValue(string valueName) + { + IgniteArgumentCheck.NotNullOrEmpty(valueName, "valueName"); + + if (!_isEnum) + { + throw new NotSupportedException("Can't get enum value for a non-enum type: " + _typeName); + } + + int res; + + return _enumNameToValue != null && _enumNameToValue.TryGetValue(valueName, out res) ? res : (int?) null; + } + + /// <summary> + /// Gets the name of the enum value. + /// </summary> + public string GetEnumName(int value) + { + if (!_isEnum) + { + throw new NotSupportedException("Can't get enum value for a non-enum type: " + _typeName); + } + + string res; + + return _enumValueToName != null && _enumValueToName.TryGetValue(value, out res) ? res : null; + } + + /// <summary> + /// Gets the enum values. + /// </summary> + private static IDictionary<string, int> GetEnumValues(IBinaryTypeDescriptor desc) + { + if (desc == null || desc.Type == null || !desc.IsEnum) + { + return null; + } + + var enumType = desc.Type; + + var values = Enum.GetValues(enumType); + var res = new Dictionary<string, int>(values.Length); + + var underlyingType = Enum.GetUnderlyingType(enumType); + + foreach (var value in values) + { + var name = Enum.GetName(enumType, value); + Debug.Assert(name != null); + + res[name] = GetEnumValueAsInt(underlyingType, value); + } + + return res; + } + + /// <summary> + /// Gets the enum value as int. + /// </summary> + private static int GetEnumValueAsInt(Type underlyingType, object value) + { + if (underlyingType == typeof(int)) + { + return (int) value; + } + + if (underlyingType == typeof(byte)) + { + return (byte) value; + } + + if (underlyingType == typeof(sbyte)) + { + return (sbyte) value; + } + + if (underlyingType == typeof(short)) + { + return (short) value; + } + + if (underlyingType == typeof(ushort)) + { + return (ushort) value; + } + + if (underlyingType == typeof(uint)) + { + return unchecked((int) (uint) value); + } + + throw new BinaryObjectException("Unexpected enum underlying type: " + underlyingType); + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c7b6f5/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs index cdbc687..7e1e970 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs @@ -17,8 +17,8 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata { - using System; using System.Collections.Generic; + using System.Diagnostics; /// <summary> /// Metadata for particular type. @@ -37,6 +37,9 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /** Enum flag. */ private readonly bool _isEnum; + /** Marshaller. */ + private readonly Marshaller _marshaller; + /** Collection of know field IDs. */ private volatile HashSet<int> _ids; @@ -46,7 +49,6 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /** Saved flag (set if type metadata was saved at least once). */ private volatile bool _saved; - /// <summary> /// Constructor. /// </summary> @@ -54,12 +56,15 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /// <param name="typeName">Type name.</param> /// <param name="affKeyFieldName">Affinity key field name.</param> /// <param name="isEnum">Enum flag.</param> - public BinaryTypeHolder(int typeId, string typeName, string affKeyFieldName, bool isEnum) + /// <param name="marshaller">The marshaller.</param> + public BinaryTypeHolder(int typeId, string typeName, string affKeyFieldName, bool isEnum, + Marshaller marshaller) { _typeId = typeId; _typeName = typeName; _affKeyFieldName = affKeyFieldName; _isEnum = isEnum; + _marshaller = marshaller; } /// <summary> @@ -100,13 +105,19 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata /// <summary> /// Merge newly sent field metadatas into existing ones. /// </summary> - /// <param name="newMap">New field metadatas map.</param> - public void Merge(IDictionary<int, Tuple<string, BinaryField>> newMap) + /// <param name="meta">Binary type to merge.</param> + public void Merge(BinaryType meta) { + Debug.Assert(meta != null); + _saved = true; - if (newMap == null || newMap.Count == 0) + var fieldsMap = meta.GetFieldsMap(); + + if (fieldsMap.Count == 0) + { return; + } lock (this) { @@ -118,20 +129,27 @@ namespace Apache.Ignite.Core.Impl.Binary.Metadata IDictionary<string, BinaryField> newFields = meta0 != null ? new Dictionary<string, BinaryField>(meta0.GetFieldsMap()) - : new Dictionary<string, BinaryField>(newMap.Count); + : new Dictionary<string, BinaryField>(fieldsMap.Count); // 2. Add new fields. - foreach (var newEntry in newMap) + foreach (var fieldMeta in fieldsMap) { - if (!newIds.Contains(newEntry.Key)) - newIds.Add(newEntry.Key); + int fieldId = BinaryUtils.FieldId(meta.TypeId, fieldMeta.Key, null, null); - if (!newFields.ContainsKey(newEntry.Value.Item1)) - newFields[newEntry.Value.Item1] = newEntry.Value.Item2; + if (!newIds.Contains(fieldId)) + { + newIds.Add(fieldId); + } + + if (!newFields.ContainsKey(fieldMeta.Key)) + { + newFields[fieldMeta.Key] = fieldMeta.Value; + } } // 3. Assign new meta. Order is important here: meta must be assigned before field IDs. - _meta = new BinaryType(_typeId, _typeName, newFields, _affKeyFieldName, _isEnum); + _meta = new BinaryType(_typeId, _typeName, newFields, _affKeyFieldName, _isEnum, + meta.EnumValuesMap, _marshaller); _ids = newIds; } }