/* Copyright (c) Microsoft Corporation All rights reserved. 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 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ using Microsoft.Research.DryadLinq; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DryadLinqTests { ////////////////////////////////////////////////////////////////////// // // Decorated and undecorated types // // A UDT with no attribute shouldn't autoserialize without an explicit [Serializable] attribute public class UDT_Undecorated { public UDT_Undecorated(int val) { m_field1 = val + 1; m_field2 = val + 2; } public int m_field1; public int m_field2; } // UDT which is marked as serializable. This should be autoserialized [Serializable] public class UDT_MarkedSerializable { public UDT_MarkedSerializable(int val) { m_field1 = val + 1; m_field2 = val + 2; } public int m_field1; public int m_field2; } // UDT that has the old style static serialization methods. This should be rejected. public class UDT_StaticSerializer { public UDT_StaticSerializer(int val) { m_field1 = val + 1; m_field2 = val + 2; } public int m_field1; public int m_field2; public static UDT_StaticSerializer Read(DryadLinqBinaryReader reader) { var val = new UDT_StaticSerializer(0); val.m_field1 = reader.ReadInt32(); val.m_field2 = reader.ReadInt32(); return val; } public static void Write(DryadLinqBinaryWriter writer, UDT_StaticSerializer val) { writer.Write(val.m_field1); writer.Write(val.m_field2); } } ////////////////////////////////////////////////////////////////////// // // UDTs with custom serializers // // UDT that has an attribute declaring itself as its custom serializer [CustomDryadLinqSerializer(typeof(UDT_SelfCustomSerializer))] public struct UDT_SelfCustomSerializer : IDryadLinqSerializer { public UDT_SelfCustomSerializer(int val) { m_field1 = val + 1; m_field2 = val + 2; } public int m_field1; public int m_field2; public UDT_SelfCustomSerializer Read(DryadLinqBinaryReader reader) { var val = new UDT_SelfCustomSerializer(0); val.m_field1 = reader.ReadInt32(); val.m_field2 = reader.ReadInt32(); return val; } public void Write(DryadLinqBinaryWriter writer, UDT_SelfCustomSerializer val) { writer.Write(val.m_field1); writer.Write(val.m_field2); } } // UDT that declares another type as its custom serializer [CustomDryadLinqSerializer(typeof(CustomUDTSerializer))] public struct UDT_ExternalCustomSerializer { public UDT_ExternalCustomSerializer(int val) { m_field1 = val + 1; m_field2 = val + 2; } public int m_field1; public int m_field2; } // this is the custom serializer for UDT_ExternalCustomSerializer public class CustomUDTSerializer : IDryadLinqSerializer { public UDT_ExternalCustomSerializer Read(DryadLinqBinaryReader reader) { var val = new UDT_ExternalCustomSerializer(0); val.m_field1 = reader.ReadInt32(); val.m_field2 = reader.ReadInt32(); return val; } public void Write(DryadLinqBinaryWriter writer, UDT_ExternalCustomSerializer val) { writer.Write(val.m_field1); writer.Write(val.m_field2); } } // UDT with a CustomHpcSerializer attribute that points to an invalid type for the serializer [CustomDryadLinqSerializer(typeof(int))] public struct UDT_BadCustomSerializerType1 { public UDT_BadCustomSerializerType1(int val) { m_field1 = val + 1; } public int m_field1; } // UDT with a CustomHpcSerializer attribute that points to a serializer type that targets a different UDT [CustomDryadLinqSerializer(typeof(CustomUDTSerializer))] public struct UDT_BadCustomSerializerType2 { public UDT_BadCustomSerializerType2(int val) { m_field1 = val + 1; } public int m_field1; } ////////////////////////////////////////////////////////////////////// // // Inheritance // // A UDT that has sub types. This should be rejected [Serializable] public class UDT_BaseType { public UDT_BaseType(int val) { m_baseTypeField = val + 42; } public int m_baseTypeField; } // A UDT that has derives from a type other than object. This should be rejected [Serializable] public class UDT_DerivedType : UDT_BaseType { public UDT_DerivedType(int val) : base(val) { m_derivedTypeField = val + 84; } public int m_derivedTypeField; } ////////////////////////////////////////////////////////////////////// // // Field types // // A UDT with no data. This should be rejected [Serializable] public class UDT_EmptyType { public UDT_EmptyType(int val) { } } // A UDT with a public field of type System.Object. This should be rejected [Serializable] public class UDT_ObjectField { public UDT_ObjectField(int val) { m_intField = val + 84; m_objectField = null; } public int m_intField; public object m_objectField; } // A UDT with a public field of type System.Object[]. This should be rejected [Serializable] public class UDT_ObjectArrayField { public UDT_ObjectArrayField(int val) { m_intField = val + 84; m_objectArrayField = new object[1]; m_objectArrayField[0] = null; } public int m_intField; public object[] m_objectArrayField; } // A UDT with a public field of type List. This should be rejected [Serializable] public class UDT_ObjectListField { public UDT_ObjectListField(int val) { m_intField = val + 84; m_objectListField = new List(); m_objectListField.Add(null); } public int m_intField; public List m_objectListField; } // A UDT with an object field, and a custom serializer. This should not be rejected [CustomDryadLinqSerializer(typeof(UDT_ObjectFieldAndCustomSerializer))] public class UDT_ObjectFieldAndCustomSerializer : IDryadLinqSerializer { private object m_objectRecord = (object)""; // Required by CustomHpcSerializer public UDT_ObjectFieldAndCustomSerializer() { } public UDT_ObjectFieldAndCustomSerializer(int val) { m_objectRecord = (object)String.Format("{0}", val); } #region IHpcSerializer implementation public UDT_ObjectFieldAndCustomSerializer Read(DryadLinqBinaryReader reader) { string tmp = reader.ReadString(); int val = Int32.Parse(tmp); return new UDT_ObjectFieldAndCustomSerializer(val); } public void Write(DryadLinqBinaryWriter writer, UDT_ObjectFieldAndCustomSerializer record) { writer.Write((string)record.m_objectRecord); } #endregion } // An empty UDT with a custom serializer. This should be rejected, because even though the user has control over serialization // we will encounter runtime problems if the custom serializer reads/writer 0 bytes. This behavior is simply to discourage empty CS code. [CustomDryadLinqSerializer(typeof(UDT_EmptyTypeWithCustomSerializer))] public class UDT_EmptyTypeWithCustomSerializer : IDryadLinqSerializer { // Required by CustomHpcSerializer public UDT_EmptyTypeWithCustomSerializer() { } public UDT_EmptyTypeWithCustomSerializer(int val) { } #region IHpcSerializer implementation public UDT_EmptyTypeWithCustomSerializer Read(DryadLinqBinaryReader reader) { return new UDT_EmptyTypeWithCustomSerializer(0); } public void Write(DryadLinqBinaryWriter writer, UDT_EmptyTypeWithCustomSerializer record) { } #endregion } ////////////////////////////////////////////////////////////////////// // // Visibility // // UDT with a field of non-public type. We cannot handle these [Serializable] public class UDT_FieldOfNonPublicType { private enum SecretCodeLevel { Secret, SuperSecret, } public UDT_FieldOfNonPublicType(int val) { m_field = (SecretCodeLevel)val; } private SecretCodeLevel m_field; } // UDT with a private field of a public type. We do handle these using emitted IL code. [Serializable] public class UDT_PrivateFieldOfPublicType { public UDT_PrivateFieldOfPublicType(int val) { m_field = val + 1; } private int m_field; } ////////////////////////////////////////////////////////////////////// // // Nesting // [Serializable] public class UDT_Nested_InnerAndOuterSerializable { public UDT_Nested_InnerAndOuterSerializable(int val) { m_field = val + 1; m_field2 = new NestedSerializable(val); } private int m_field; private NestedSerializable m_field2; [Serializable] public class NestedSerializable { public NestedSerializable(int val) { m_field = val / 2.0; } private double m_field; } } [Serializable] public class UDT_Nested_InnerEnum_InnerAndOuterSerializable { public UDT_Nested_InnerEnum_InnerAndOuterSerializable(int val) { m_field = val + 1; m_field2 = (NestedEnum)(val % 3); } private int m_field; private NestedEnum m_field2; //[Serializable] public enum NestedEnum { Foo = 0, Bar = 1, Baz = 2, } } [Serializable] public class UDT_Nested_OuterSerializableInnerNotSerializable { public UDT_Nested_OuterSerializableInnerNotSerializable(int val) { m_field = val + 1; m_field2 = new NestedNotSerializable(val); } private int m_field; private NestedNotSerializable m_field2; public class NestedNotSerializable { public NestedNotSerializable(int val) { m_field = val / 2.0; } private double m_field; } } public class UDT_Nested_OuterNotSerializableInnerSerializable { public UDT_Nested_OuterNotSerializableInnerSerializable(int val) { m_field = val + 1; m_field2 = new NestedSerializable(val); } private int m_field; private NestedSerializable m_field2; [Serializable] public class NestedSerializable { public NestedSerializable(int val) { m_field = val / 2.0; } private double m_field; } } ////////////////////////////////////////////////////////////////////// // // Self reference // // First level circular type [Serializable] public class UDT_FirstLevelCircular { public UDT_FirstLevelCircular(int val) { m_field1 = val + 1; m_field2 = val + 2; m_circularRef = null; } public int m_field1; public int m_field2; public UDT_FirstLevelCircular m_circularRef; } // First level circular type with an array reference to self [Serializable] public class UDT_FirstLevelCircularArrayRef { public UDT_FirstLevelCircularArrayRef(int val) { m_field1 = val + 1; m_field2 = val + 2; m_circularRefArray = new UDT_FirstLevelCircular[5]; } public int m_field1; public int m_field2; public UDT_FirstLevelCircular[] m_circularRefArray; } // Second level circular type [Serializable] public class UDT_SecondLevelCircular { public UDT_SecondLevelCircular(int val) { m_field1 = val + 1; m_field2 = val + 2; m_child = new UDT_CircularRefChild(this); } public int m_field1; public int m_field2; public UDT_CircularRefChild m_child; } [Serializable] public class UDT_CircularRefChild { public UDT_CircularRefChild(UDT_SecondLevelCircular parent) { m_parent = parent; } public UDT_SecondLevelCircular m_parent; } // Circular type with custom serializer. Should not be rejected [CustomDryadLinqSerializer(typeof(UDT_CircularTypeWithCustomSerializer))] public class UDT_CircularTypeWithCustomSerializer : IDryadLinqSerializer { public UDT_CircularTypeWithCustomSerializer() { } public UDT_CircularTypeWithCustomSerializer(int val) { m_field1 = val; // create each new object with log2(val) self references hanging off of m_next if (val == 0) m_next = null; else m_next = new UDT_CircularTypeWithCustomSerializer(val / 2); } public int m_field1; public UDT_CircularTypeWithCustomSerializer m_next; // // sample recursive custom serializer // public UDT_CircularTypeWithCustomSerializer Read(DryadLinqBinaryReader reader) { UDT_CircularTypeWithCustomSerializer obj = new UDT_CircularTypeWithCustomSerializer(); bool bHasValidNext = reader.ReadBool(); obj.m_field1 = reader.ReadInt32(); if (bHasValidNext) { obj.m_next = this.Read(reader); // recursively read the next } else { obj.m_next = null; // terminate recursion } return obj; } public void Write(DryadLinqBinaryWriter writer, UDT_CircularTypeWithCustomSerializer x) { if (x.m_next != null) { writer.Write(true); // bHasValidNext for the reader side writer.Write(x.m_field1); this.Write(writer, x.m_next); // write out recursively } else { writer.Write(false); // bHasValidNext = false for the reader side, makes sure recursive reads stop writer.Write(x.m_field1); } } } // This type itself isn't circular, but contains a field of a circular type that is custom serialized. Autoserialization should work for this guy [Serializable] public class UDT_TypeContainingCustomSerializedCircularType { public UDT_TypeContainingCustomSerializedCircularType(int val) { m_field1 = val; m_circularType = new UDT_CircularTypeWithCustomSerializer(val); } public int m_field1; public UDT_CircularTypeWithCustomSerializer m_circularType; } }