Click here to Skip to main content
15,895,777 members
Articles / Programming Languages / C#

A Fast/Compact Serialization Framework

Rate me:
Please Sign up or sign in to vote.
4.85/5 (37 votes)
13 Oct 2010GPL35 min read 284.2K   1.2K   175  
A framework for object serializiation/deserialization that is many times faster and yields a compact output.
/*

Compact Serialization Framework
Copyright (C) 2006 Shoaib Ali

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

for bug-reports and suggestions alleey@gmail.com

*/
using System;
using System.Collections;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;

using CompactSerialization.IO;

namespace CompactSerialization.Surrogates
{
	#region /       Default surrogates       /

	/// <summary>
	/// Surrogate for null values. 
	/// </summary>
	sealed class NullSerializationSurrogate: SerializationSurrogate
	{
		public NullSerializationSurrogate():base(typeof(NullSerializationSurrogate)) {}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Object"/> objects. Also serves the
	/// purpose of default surrogate. It uses .NET native serialization
	/// </summary>
	sealed class ObjectSerializationSurrogate: SerializationSurrogate
	{
		static BinaryFormatter formatter = new BinaryFormatter();

		public ObjectSerializationSurrogate(Type t):base(t) {}

		/// <summary>
		/// Uses a <see cref="BinaryFormatter"/> to read an object of 
		/// type <see cref="ActualType"/> from the underlying stream.
		/// </summary>
		/// <param name="reader">stream reader</param>
		/// <returns>object read from the stream reader</returns>
		public override object Read(CompactBinaryReader reader)
		{
			return formatter.Deserialize(reader.BaseReader.BaseStream);
		}

		/// <summary>
		/// Uses a <see cref="BinaryFormatter"/> to write an object of 
		/// type <see cref="ActualType"/> to the underlying stream
		/// </summary>
		/// <param name="writer">stream writer</param>
		/// <param name="graph">object to be written to the stream reader</param>
		public override void Write(CompactBinaryWriter writer, object graph)
		{
			formatter.Serialize(writer.BaseWriter.BaseStream, graph);
		}
	}


	/// <summary>
	/// Surrogate for <see cref="System.object[]"/> type.
	/// </summary>
	sealed class ObjectArraySerializationSurrogate: SerializationSurrogate
	{
		public ObjectArraySerializationSurrogate() : base(typeof(object[])) { }

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			object[] array = new object[length];
			for (int i = 0; i < length; i++) array[i] = reader.Read();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			object[] array = (object[])graph;
			writer.Write(array.Length);
			for (int i = 0; i < array.Length; i++)
				writer.Write(array[i]);
		}
	}

	#endregion

	#region /       .NET Primitive Types' surrogates       /

	/// <summary>
	/// Surrogate for <see cref="System.Boolean"/> type.
	/// </summary>
	sealed class BooleanSerializationSurrogate: SerializationSurrogate
	{
		public BooleanSerializationSurrogate():base(typeof(Boolean)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadBoolean(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Boolean)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Boolean[]"/> type.
	/// </summary>
	sealed class BooleanArraySerializationSurrogate: SerializationSurrogate
	{
		public BooleanArraySerializationSurrogate():base(typeof(Boolean[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Boolean[] array = new Boolean[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadBoolean();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Boolean[] array = (Boolean[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Byte"/> type.
	/// </summary>
	sealed class ByteSerializationSurrogate: SerializationSurrogate
	{
		public ByteSerializationSurrogate():base(typeof(Byte)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadByte(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Byte)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Byte[]"/> type.
	/// </summary>
	sealed class ByteArraySerializationSurrogate: SerializationSurrogate
	{
		public ByteArraySerializationSurrogate():base(typeof(Byte[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			return reader.ReadBytes(length);
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Byte[] array = (Byte[]) graph;
			writer.Write(array.Length);
			writer.Write(array);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Char"/> type.
	/// </summary>
	sealed class CharSerializationSurrogate: SerializationSurrogate
	{
		public CharSerializationSurrogate():base(typeof(Char)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadChar(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Char)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Char[]"/> type.
	/// </summary>
	sealed class CharArraySerializationSurrogate: SerializationSurrogate
	{
		public CharArraySerializationSurrogate():base(typeof(Char[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			return reader.ReadChars(length);
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Char[] array = (Char[]) graph;
			writer.Write(array.Length);
			writer.Write(array);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Single"/> type.
	/// </summary>
	sealed class SingleSerializationSurrogate: SerializationSurrogate
	{
		public SingleSerializationSurrogate():base(typeof(Single)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadSingle(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Single)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Single[]"/> type.
	/// </summary>
	sealed class SingleArraySerializationSurrogate: SerializationSurrogate
	{
		public SingleArraySerializationSurrogate():base(typeof(Single[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Single[] array = new Single[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadSingle();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Single[] array = (Single[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Double"/> type.
	/// </summary>
	sealed class DoubleSerializationSurrogate: SerializationSurrogate
	{
		public DoubleSerializationSurrogate():base(typeof(Double)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadDouble(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Double)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Double[]"/> type.
	/// </summary>
	sealed class DoubleArraySerializationSurrogate: SerializationSurrogate
	{
		public DoubleArraySerializationSurrogate():base(typeof(Double[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Double[] array = new Double[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadDouble();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Double[] array = (Double[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Decimal"/> type.
	/// </summary>
	sealed class DecimalSerializationSurrogate: SerializationSurrogate
	{
		public DecimalSerializationSurrogate():base(typeof(Decimal)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadDecimal(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Decimal)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Decimal[]"/> type.
	/// </summary>
	sealed class DecimalArraySerializationSurrogate: SerializationSurrogate
	{
		public DecimalArraySerializationSurrogate():base(typeof(Decimal)) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Decimal[] array = new Decimal[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadDecimal();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Decimal[] array = (Decimal[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Int16"/> type.
	/// </summary>
	sealed class Int16SerializationSurrogate: SerializationSurrogate
	{
		public Int16SerializationSurrogate():base(typeof(Int16)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadInt16(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Int16)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Int16[]"/> type.
	/// </summary>
	sealed class Int16ArraySerializationSurrogate: SerializationSurrogate
	{
		public Int16ArraySerializationSurrogate():base(typeof(Int16[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Int16[] array = new Int16[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadInt16();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Int16[] array = (Int16[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Int32"/> type.
	/// </summary>
	sealed class Int32SerializationSurrogate: SerializationSurrogate
	{
		public Int32SerializationSurrogate():base(typeof(Int32)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadInt32(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((int)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Int32[]"/> type.
	/// </summary>
	sealed class Int32ArraySerializationSurrogate: SerializationSurrogate
	{
		public Int32ArraySerializationSurrogate():base(typeof(Int32[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Int32[] array = new Int32[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadInt32();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Int32[] array = (Int32[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.Int64"/> type.
	/// </summary>
	sealed class Int64SerializationSurrogate: SerializationSurrogate
	{
		public Int64SerializationSurrogate():base(typeof(Int64)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadInt64(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((Int64)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.Int64[]"/> type.
	/// </summary>
	sealed class Int64ArraySerializationSurrogate: SerializationSurrogate
	{
		public Int64ArraySerializationSurrogate():base(typeof(Int64)) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Int64[] array = new Int64[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadInt64();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Int64[] array = (Int64[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.DateTime"/> type.
	/// </summary>
	sealed class DateTimeSerializationSurrogate : SerializationSurrogate
	{
		public DateTimeSerializationSurrogate() : base(typeof(DateTime)) { }
		public override object Read(CompactBinaryReader reader) { return reader.ReadDateTime(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((DateTime)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.DateTime[]"/> type.
	/// </summary>
	sealed class DateTimeArraySerializationSurrogate : SerializationSurrogate
	{
		public DateTimeArraySerializationSurrogate() : base(typeof(DateTime[])) { }

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			DateTime[] array = new DateTime[length];
			for (int i = 0; i < length; i++) array[i] = reader.ReadDateTime();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			DateTime[] array = (DateTime[])graph;
			writer.Write(array.Length);
			for (int i = 0; i < array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.String"/> type.
	/// </summary>
	sealed class StringSerializationSurrogate: SerializationSurrogate
	{
		public StringSerializationSurrogate():base(typeof(String)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadString(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((string)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.String[]"/> type.
	/// </summary>
	sealed class StringArraySerializationSurrogate: SerializationSurrogate
	{
		public StringArraySerializationSurrogate():base(typeof(String[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			String[] array = new String[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadString();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			String[] array = (String[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.SByte"/> type.
	/// </summary>
	sealed class SByteSerializationSurrogate: SerializationSurrogate
	{
		public SByteSerializationSurrogate():base(typeof(SByte)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadSByte(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((SByte)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.SByte[]"/> type.
	/// </summary>
	sealed class SByteArraySerializationSurrogate: SerializationSurrogate
	{
		public SByteArraySerializationSurrogate():base(typeof(SByte[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			SByte[] array = new SByte[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadSByte();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			SByte[] array = (SByte[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.UInt16"/> type.
	/// </summary>
	sealed class UInt16SerializationSurrogate: SerializationSurrogate
	{
		public UInt16SerializationSurrogate():base(typeof(UInt16)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadUInt16(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((UInt16)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.UInt16[]"/> type.
	/// </summary>
	sealed class UInt16ArraySerializationSurrogate: SerializationSurrogate
	{
		public UInt16ArraySerializationSurrogate():base(typeof(UInt16[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			UInt16[] array = new UInt16[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadUInt16();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			UInt16[] array = (UInt16[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.UInt32"/> type.
	/// </summary>
	sealed class UInt32SerializationSurrogate: SerializationSurrogate
	{
		public UInt32SerializationSurrogate():base(typeof(UInt32)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadUInt32(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((UInt32)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.UInt32[]"/> type.
	/// </summary>
	sealed class UInt32ArraySerializationSurrogate: SerializationSurrogate
	{
		public UInt32ArraySerializationSurrogate():base(typeof(UInt32[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			UInt32[] array = new UInt32[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadUInt32();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			UInt32[] array = (UInt32[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	/// <summary>
	/// Surrogate for <see cref="System.UInt64"/> type.
	/// </summary>
	sealed class UInt64SerializationSurrogate: SerializationSurrogate
	{
		public UInt64SerializationSurrogate():base(typeof(UInt64)) {}
		public override object Read(CompactBinaryReader reader) { return reader.ReadUInt64(); }
		public override void Write(CompactBinaryWriter writer, object graph) { writer.Write((UInt64)graph); }
	}

	/// <summary>
	/// Surrogate for <see cref="System.UInt64[]"/> type.
	/// </summary>
	sealed class UInt64ArraySerializationSurrogate: SerializationSurrogate
	{
		public UInt64ArraySerializationSurrogate():base(typeof(UInt64[])) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			UInt64[] array = new UInt64[length];
			for(int i=0; i<length; i++) array[i] = reader.ReadUInt64();
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			UInt64[] array = (UInt64[]) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array[i]);
		}
	}

	#endregion

	#region /       Generic surrogates for containers      /

	/// <summary>
	/// Surrogate for generic <see cref="System.Array"/> types.
	/// </summary>
	sealed class ArraySerializationSurrogate: SerializationSurrogate
	{
		public ArraySerializationSurrogate(Type t):base(t) {}

		public Array CreateInstance(int len)
		{
			return Array.CreateInstance(ActualType.GetElementType(), len);
		}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			Array array = (Array) CreateInstance(length);
			for(int i=0; i<length; i++)
				array.SetValue(reader.Read(), i);
			return array;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			Array array = (Array) graph;
			writer.Write(array.Length);
			for(int i=0; i<array.Length; i++)
				writer.Write(array.GetValue(i));
		}
	}

	/// <summary>
	/// Surrogate for types that inherit from <see cref="System.IList"/>.
	/// </summary>
	sealed class IListSerializationSurrogate: SerializationSurrogate
	{
		public IListSerializationSurrogate(Type t):base(t) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			IList list = (IList) CreateInstance();
			for(int i=0; i<length; i++)
				list.Add(reader.Read());
			return list;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			IList list = (IList) graph;
			writer.Write(list.Count);
			for(int i=0; i<list.Count; i++)
				writer.Write(list[i]);
		}
	}

	/// <summary>
	/// Surrogate for types that inherit from <see cref="System.IDictionary"/>.
	/// </summary>
	sealed class IDictionarySerializationSurrogate: SerializationSurrogate
	{
		public IDictionarySerializationSurrogate(Type t):base(t) {}

		public override object Read(CompactBinaryReader reader)
		{
			int length = reader.ReadInt32();
			IDictionary dict = (IDictionary) CreateInstance();
			for(int i=0; i<length; i++)
			{
				object key = reader.Read();
				object value = reader.Read();
				dict.Add(key, value);
			}
			return dict;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			IDictionary dict = (IDictionary) graph;
			writer.Write(dict.Count);
			for(IDictionaryEnumerator i=dict.GetEnumerator(); i.MoveNext(); )
			{
				writer.Write(i.Key);
				writer.Write(i.Value);
			}
		}
	}


	#endregion
	
	/// <summary>
	/// Surrogate for types that inherit from <see cref="ICompactSerializable"/>.
	/// </summary>
	sealed class ICompactSerializableSerializationSurrogate: SerializationSurrogate
	{
		public ICompactSerializableSerializationSurrogate(Type t):base(t) {}

		/// <summary>
		/// Non default object construction. The idea is to circumvent constructor calls
		/// and populate the object in <see cref="ICompactSerializable.Deserialize"/> method.
		/// </summary>
		/// <returns></returns>
		public override object CreateInstance()
		{
			return FormatterServices.GetUninitializedObject(ActualType);
		}

		public override object Read(CompactBinaryReader reader)
		{
			ICompactSerializable custom = (ICompactSerializable) CreateInstance();
			custom.Deserialize(reader);
			return custom;
		}

		public override void Write(CompactBinaryWriter writer, object graph)
		{
			((ICompactSerializable)graph).Serialize(writer);
		}
	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Architect
Pakistan Pakistan
Let a = b ....... (1)
a - b = a - b
a^2 - ab = a^2 - ab
a^2 - ab = a^2 - b^2 (from 1)
a (a - b) = (a + b) (a - b)
a = (a + b) ...... (2)

if a = 1
1 = (1 + 1) (from 1 & 2)
1 = 2 !!

Comments and Discussions