Skip to content

Commit

Permalink
Implemented StackSerializer.
Browse files Browse the repository at this point in the history
  • Loading branch information
rstam committed Nov 1, 2010
1 parent dea18ba commit d733e05
Show file tree
Hide file tree
Showing 4 changed files with 335 additions and 0 deletions.
1 change: 1 addition & 0 deletions Bson/Bson.csproj
Expand Up @@ -90,6 +90,7 @@
<Compile Include="DefaultSerializer\Serializers\NullableTypeSerializer.cs" />
<Compile Include="DefaultSerializer\Serializers\ObjectSerializer.cs" />
<Compile Include="DefaultSerializer\Serializers\QueueSerializers.cs" />
<Compile Include="DefaultSerializer\Serializers\StackSerializers.cs" />
<Compile Include="Exceptions\BsonInternalException.cs" />
<Compile Include="Exceptions\BsonSerializationException.cs" />
<Compile Include="ObjectModel\IConvertibleToBsonDocument.cs" />
Expand Down
170 changes: 170 additions & 0 deletions Bson/DefaultSerializer/Serializers/StackSerializers.cs
@@ -0,0 +1,170 @@
/* Copyright 2010 10gen 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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;

namespace MongoDB.Bson.DefaultSerializer {
public class StackSerializer : BsonBaseSerializer {
#region private static fields
private static StackSerializer singleton = new StackSerializer();
#endregion

#region constructors
private StackSerializer() {
}
#endregion

#region public static properties
public static StackSerializer Singleton {
get { return singleton; }
}
#endregion

#region public static methods
public static void RegisterSerializers() {
BsonSerializer.RegisterSerializer(typeof(Stack), singleton);
}
#endregion

#region public methods
public override object DeserializeElement(
BsonReader bsonReader,
Type nominalType,
out string name
) {
var bsonType = bsonReader.PeekBsonType();
if (bsonType == BsonType.Null) {
bsonReader.ReadNull(out name);
return null;
} else if (bsonType == BsonType.Array) {
bsonReader.ReadArrayName(out name);
bsonReader.ReadStartDocument();
var stack = new Stack();
while (bsonReader.HasElement()) {
var elementType = BsonClassMapSerializer.GetActualElementType(bsonReader, typeof(object));
var serializer = BsonSerializer.LookupSerializer(elementType);
string elementName; // elementNames are ignored on input
var element = serializer.DeserializeElement(bsonReader, typeof(object), out elementName);
stack.Push(element);
}
bsonReader.ReadEndDocument();
return stack;
} else {
var message = string.Format("Can't deserialize a {0} from BsonType {1}", nominalType.FullName, bsonType);
throw new FileFormatException(message);
}
}

public override void SerializeElement(
BsonWriter bsonWriter,
Type nominalType,
string name,
object value
) {
if (value == null) {
bsonWriter.WriteNull(name);
} else {
bsonWriter.WriteArrayName(name);
bsonWriter.WriteStartDocument();
var outputOrder = new ArrayList((Stack) value); // serialize first pushed item first (reverse of enumerator order)
outputOrder.Reverse();
int index = 0;
foreach (var element in outputOrder) {
var elementName = index.ToString();
BsonSerializer.SerializeElement(bsonWriter, typeof(object), elementName, element);
index++;
}
bsonWriter.WriteEndDocument();
}
}
#endregion
}

public static class StackSerializerRegistration {
#region public static methods
public static void RegisterGenericSerializerDefinitions() {
BsonDefaultSerializationProvider.RegisterGenericSerializerDefinition(typeof(Stack<>), typeof(StackSerializer<>));
}
#endregion
}

public class StackSerializer<T> : BsonBaseSerializer {
#region constructors
public StackSerializer() {
}
#endregion

#region public methods
public override object DeserializeElement(
BsonReader bsonReader,
Type nominalType,
out string name
) {
var bsonType = bsonReader.PeekBsonType();
if (bsonType == BsonType.Null) {
bsonReader.ReadNull(out name);
return null;
} else if (bsonType == BsonType.Array) {
bsonReader.ReadArrayName(out name);
bsonReader.ReadStartDocument();
var stack = new Stack<T>();
while (bsonReader.HasElement()) {
var elementType = BsonClassMapSerializer.GetActualElementType(bsonReader, typeof(T));
var serializer = BsonSerializer.LookupSerializer(elementType);
string elementName; // elementNames are ignored on input
var element = (T) serializer.DeserializeElement(bsonReader, typeof(T), out elementName);
stack.Push(element);
}
bsonReader.ReadEndDocument();
return stack;
} else {
var message = string.Format("Can't deserialize a {0} from BsonType {1}", nominalType.FullName, bsonType);
throw new FileFormatException(message);
}
}

public override void SerializeElement(
BsonWriter bsonWriter,
Type nominalType,
string name,
object value
) {
if (value == null) {
bsonWriter.WriteNull(name);
} else {
bsonWriter.WriteArrayName(name);
bsonWriter.WriteStartDocument();
var outputOrder = new List<T>((Stack<T>) value); // serialize first pushed item first (reverse of enumerator order)
outputOrder.Reverse();
int index = 0;
foreach (var element in outputOrder) {
var elementName = index.ToString();
BsonSerializer.SerializeElement(bsonWriter, typeof(T), elementName, element);
index++;
}
bsonWriter.WriteEndDocument();
}
}
#endregion
}
}
1 change: 1 addition & 0 deletions BsonUnitTests/BsonUnitTests.csproj
Expand Up @@ -84,6 +84,7 @@
<Compile Include="DefaultSerializer\Serializers\EnumerableSerializerTests.cs" />
<Compile Include="DefaultSerializer\Serializers\NullableTypeSerializerTests.cs" />
<Compile Include="DefaultSerializer\Serializers\QueueSerializerTests.cs" />
<Compile Include="DefaultSerializer\Serializers\StackSerializerTests.cs" />
<Compile Include="IO\BsonBufferValueStraddlesChunksTests.cs" />
<Compile Include="Jira\CSharp70Tests.cs" />
<Compile Include="Jira\CSharp71Tests.cs" />
Expand Down
163 changes: 163 additions & 0 deletions BsonUnitTests/DefaultSerializer/Serializers/StackSerializerTests.cs
@@ -0,0 +1,163 @@
/* Copyright 2010 10gen 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;
using System.Linq;
using System.Text;
using NUnit.Framework;

using MongoDB.Bson;
using MongoDB.Bson.DefaultSerializer;
using MongoDB.Bson.Serialization;

namespace MongoDB.BsonUnitTests.DefaultSerializer.StackSerializer {
[BsonDiscriminator("StackSerializer.C")] // "C" is an ambiguous discriminator when nominalType is System.Object
public class C {
public string P { get; set; }
}

[TestFixture]
public class StackSerializerTests {
public class T {
public Stack S { get; set; }
}

[Test]
public void TestNull() {
var obj = new T { S = null };
var json = obj.ToJson();
var expected = "{ 'S' : null }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsNull(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestEmpty() {
var obj = new T { S = new Stack() };
var json = obj.ToJson();
var expected = "{ 'S' : [] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestOneC() {
var obj = new T { S = new Stack(new[] { new C { P = "x" } }) };
var json = obj.ToJson();
var expected = "{ 'S' : [{ '_t' : 'StackSerializer.C', 'P' : 'x' }] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestOneInt() {
var obj = new T { S = new Stack(new[] { 1 }) };
var json = obj.ToJson();
var expected = "{ 'S' : [1] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestOneString() {
var obj = new T { S = new Stack(new[] { "x" }) };
var json = obj.ToJson();
var expected = "{ 'S' : ['x'] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestTwoCs() {
var obj = new T { S = new Stack(new[] { new C { P = "x" }, new C { P = "y" } }) };
var json = obj.ToJson();
var expected = "{ 'S' : [{ '_t' : 'StackSerializer.C', 'P' : 'x' }, { '_t' : 'StackSerializer.C', 'P' : 'y' }] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestTwoInts() {
var obj = new T { S = new Stack(new[] { 1, 2 }) };
var json = obj.ToJson();
var expected = "{ 'S' : [1, 2] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestTwoStrings() {
var obj = new T { S = new Stack(new[] { "x", "y" }) };
var json = obj.ToJson();
var expected = "{ 'S' : ['x', 'y'] }".Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}

[Test]
public void TestMixedPrimitiveTypes() {
var dateTime = DateTime.SpecifyKind(new DateTime(2010, 1, 1, 11, 22, 33), DateTimeKind.Utc);
var millis = (long) ((dateTime - BsonConstants.UnixEpoch).TotalMilliseconds);
var guid = Guid.Empty;
var objectId = ObjectId.Empty;
var obj = new T { S = new Stack(new object[] { true, dateTime, 1.5, 1, 2L, guid, objectId, "x" }) };
var json = obj.ToJson();
var expected = "{ 'S' : [true, #Date, 1.5, 1, 2, #Guid, #ObjectId, 'x'] }";
expected = expected.Replace("#Date", "{ '$date' : #ms }".Replace("#ms", millis.ToString()));
expected = expected.Replace("#Guid", "{ '$binary' : 'AAAAAAAAAAAAAAAAAAAAAA==', '$type' : '03' }");
expected = expected.Replace("#ObjectId", "{ '$oid' : '000000000000000000000000' }");
expected = expected.Replace("'", "\"");
Assert.AreEqual(expected, json);

var bson = obj.ToBson();
var rehydrated = BsonSerializer.DeserializeDocument<T>(bson);
Assert.IsInstanceOf<Stack>(rehydrated.S);
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
}
}
}

0 comments on commit d733e05

Please sign in to comment.