/* Copyright 2010-present MongoDB Inc.
*
* Licensed 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.
*/
using System;
using System.Collections.Generic;
using System.IO;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.Options;
namespace MongoDB.Bson.Serialization.Serializers
{
///
/// Represents a serializer for KeyValuePairs.
///
/// The type of the keys.
/// The type of the values.
public class KeyValuePairSerializer :
StructSerializerBase>,
IBsonDocumentSerializer
{
// private constants
private static class Flags
{
public const long Key = 1;
public const long Value = 2;
}
// private fields
private readonly SerializerHelper _helper;
private readonly Lazy> _lazyKeySerializer;
private readonly BsonType _representation;
private readonly Lazy> _lazyValueSerializer;
// constructors
///
/// Initializes a new instance of the class.
///
public KeyValuePairSerializer()
: this(BsonType.Document)
{
}
///
/// Initializes a new instance of the class.
///
/// The representation.
public KeyValuePairSerializer(BsonType representation)
: this(representation, BsonSerializer.SerializerRegistry)
{
}
///
/// Initializes a new instance of the class.
///
/// The representation.
/// The key serializer.
/// The value serializer.
public KeyValuePairSerializer(BsonType representation, IBsonSerializer keySerializer, IBsonSerializer valueSerializer)
: this(
representation,
new Lazy>(() => keySerializer),
new Lazy>(() => valueSerializer))
{
if (keySerializer == null)
{
throw new ArgumentNullException("keySerializer");
}
if (valueSerializer == null)
{
throw new ArgumentNullException("valueSerializer");
}
}
///
/// Initializes a new instance of the class.
///
/// The representation.
/// The serializer registry.
public KeyValuePairSerializer(BsonType representation, IBsonSerializerRegistry serializerRegistry)
: this(
representation,
new Lazy>(() => serializerRegistry.GetSerializer()),
new Lazy>(() => serializerRegistry.GetSerializer()))
{
if (serializerRegistry == null)
{
throw new ArgumentNullException("serializerRegistry");
}
}
private KeyValuePairSerializer(BsonType representation, Lazy> lazyKeySerializer, Lazy> lazyValueSerializer)
{
switch (representation)
{
case BsonType.Array:
case BsonType.Document:
break;
default:
var message = string.Format("{0} is not a valid representation for a KeyValuePairSerializer.", representation);
throw new ArgumentException(message);
}
_representation = representation;
_lazyKeySerializer = lazyKeySerializer;
_lazyValueSerializer = lazyValueSerializer;
_helper = new SerializerHelper
(
new SerializerHelper.Member("k", Flags.Key),
new SerializerHelper.Member("v", Flags.Value)
);
}
// public properties
///
/// Gets the key serializer.
///
///
/// The key serializer.
///
public IBsonSerializer KeySerializer
{
get { return _lazyKeySerializer.Value; }
}
///
/// Gets the representation.
///
///
/// The representation.
///
public BsonType Representation
{
get { return _representation; }
}
///
/// Gets the value serializer.
///
///
/// The value serializer.
///
public IBsonSerializer ValueSerializer
{
get { return _lazyValueSerializer.Value; }
}
// public methods
///
/// Deserializes a value.
///
/// The deserialization context.
/// The deserialization args.
/// A deserialized value.
public override KeyValuePair Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
switch (bsonType)
{
case BsonType.Array:
return DeserializeArrayRepresentation(context);
case BsonType.Document:
return DeserializeDocumentRepresentation(context);
default:
throw CreateCannotDeserializeFromBsonTypeException(bsonType);
}
}
///
/// Serializes a value.
///
/// The serialization context.
/// The serialization args.
/// The object.
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, KeyValuePair value)
{
switch (_representation)
{
case BsonType.Array:
SerializeArrayRepresentation(context, value);
break;
case BsonType.Document:
SerializeDocumentRepresentation(context, value);
break;
default:
var message = string.Format(
"'{0}' is not a valid {1} representation.",
_representation,
BsonUtils.GetFriendlyTypeName(typeof(KeyValuePair)));
throw new BsonSerializationException(message);
}
}
///
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
{
if (_representation != BsonType.Document)
{
serializationInfo = null;
return false;
}
switch (memberName)
{
case "Key":
serializationInfo = new BsonSerializationInfo("k", _lazyKeySerializer.Value, _lazyKeySerializer.Value.ValueType);
return true;
case "Value":
serializationInfo = new BsonSerializationInfo("v", _lazyValueSerializer.Value, _lazyValueSerializer.Value.ValueType);
return true;
}
serializationInfo = null;
return false;
}
// private methods
private KeyValuePair DeserializeArrayRepresentation(BsonDeserializationContext context)
{
var bsonReader = context.Reader;
bsonReader.ReadStartArray();
var key = _lazyKeySerializer.Value.Deserialize(context);
var value = _lazyValueSerializer.Value.Deserialize(context);
bsonReader.ReadEndArray();
return new KeyValuePair(key, value);
}
private KeyValuePair DeserializeDocumentRepresentation(BsonDeserializationContext context)
{
var key = default(TKey);
var value = default(TValue);
_helper.DeserializeMembers(context, (elementName, flag) =>
{
switch (flag)
{
case Flags.Key: key = _lazyKeySerializer.Value.Deserialize(context); break;
case Flags.Value: value = _lazyValueSerializer.Value.Deserialize(context); break;
}
});
return new KeyValuePair(key, value);
}
private void SerializeArrayRepresentation(BsonSerializationContext context, KeyValuePair value)
{
var bsonWriter = context.Writer;
bsonWriter.WriteStartArray();
_lazyKeySerializer.Value.Serialize(context, value.Key);
_lazyValueSerializer.Value.Serialize(context, value.Value);
bsonWriter.WriteEndArray();
}
private void SerializeDocumentRepresentation(BsonSerializationContext context, KeyValuePair value)
{
var bsonWriter = context.Writer;
bsonWriter.WriteStartDocument();
bsonWriter.WriteName("k");
_lazyKeySerializer.Value.Serialize(context, value.Key);
bsonWriter.WriteName("v");
_lazyValueSerializer.Value.Serialize(context, value.Value);
bsonWriter.WriteEndDocument();
}
}
}